* Added a wait_for_thread_etc() function that allows specifying semaphore flags

and a timeout.
* _user_wait_for_thread() was not interruptible before, ie. Control-C wouldn't
  work.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16654 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-03-08 16:41:03 +00:00
parent f8f104b2e1
commit 33a9adb376
2 changed files with 68 additions and 62 deletions

View File

@ -61,6 +61,8 @@ thread_id peek_next_thread_id(void);
thread_id spawn_kernel_thread_etc(thread_func, const char *name, int32 priority,
void *args, team_id team, thread_id threadID);
status_t wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
status_t *_returnCode);
// used in syscalls.c
status_t _user_set_thread_priority(thread_id thread, int32 newPriority);

View File

@ -1164,8 +1164,7 @@ thread_at_kernel_exit(void)
}
// #pragma mark -
// private kernel exported functions
// #pragma mark - private kernel API
/** Insert a thread to the tail of a queue
@ -1281,6 +1280,66 @@ spawn_kernel_thread_etc(thread_func function, const char *name, int32 priority,
}
status_t
wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout, status_t *_returnCode)
{
sem_id sem = B_BAD_THREAD_ID;
struct death_entry death;
struct thread *thread;
cpu_status state;
status_t status;
// we need to resume the thread we're waiting for first
status = resume_thread(id);
if (status != B_OK)
return status;
state = disable_interrupts();
GRAB_THREAD_LOCK();
thread = thread_get_thread_struct_locked(id);
if (thread != NULL) {
// remember the semaphore we have to wait on and place our death entry
sem = thread->exit.sem;
list_add_link_to_head(&thread->exit.waiters, &death);
}
RELEASE_THREAD_LOCK();
restore_interrupts(state);
if (sem < B_OK)
return B_BAD_THREAD_ID;
status = acquire_sem_etc(sem, 1, flags, timeout);
if (status == B_OK) {
// this should never happen as the thread deletes the semaphore on exit
panic("could acquire exit_sem for thread %lx\n", id);
} else if (status == B_BAD_SEM_ID) {
// this is the way the thread normally exits
status = B_OK;
if (_returnCode)
*_returnCode = death.status;
} else {
// We were probably interrupted; we need to remove our death entry now.
// When the thread is already gone, we don't have to care
state = disable_interrupts();
GRAB_THREAD_LOCK();
thread = thread_get_thread_struct_locked(id);
if (thread != NULL)
list_remove_link(&death);
RELEASE_THREAD_LOCK();
restore_interrupts(state);
}
return status;
}
int32
thread_max_threads(void)
{
@ -1415,8 +1474,7 @@ thread_per_cpu_init(int32 cpuNum)
}
// #pragma mark -
// public kernel exported functions
// #pragma mark - public kernel API
void
@ -1841,62 +1899,9 @@ snooze_until(bigtime_t timeout, int timebase)
status_t
wait_for_thread(thread_id id, status_t *_returnCode)
wait_for_thread(thread_id thread, status_t *_returnCode)
{
sem_id sem = B_BAD_THREAD_ID;
struct death_entry death;
struct thread *thread;
cpu_status state;
status_t status;
// we need to resume the thread we're waiting for first
status = resume_thread(id);
if (status != B_OK)
return status;
state = disable_interrupts();
GRAB_THREAD_LOCK();
thread = thread_get_thread_struct_locked(id);
if (thread != NULL) {
// remember the semaphore we have to wait on and place our death entry
sem = thread->exit.sem;
list_add_link_to_head(&thread->exit.waiters, &death);
}
RELEASE_THREAD_LOCK();
restore_interrupts(state);
if (sem < B_OK)
return B_BAD_THREAD_ID;
status = acquire_sem(sem);
if (status == B_OK) {
// this should never happen as the thread deletes the semaphore on exit
panic("could acquire exit_sem for thread %lx\n", id);
} else if (status == B_BAD_SEM_ID) {
// this is the way the thread normally exits
status = B_OK;
if (_returnCode)
*_returnCode = death.status;
} else {
// We were probably interrupted; we need to remove our death entry now.
// When the thread is already gone, we don't have to care
state = disable_interrupts();
GRAB_THREAD_LOCK();
thread = thread_get_thread_struct_locked(id);
if (thread != NULL)
list_remove_link(&death);
RELEASE_THREAD_LOCK();
restore_interrupts(state);
}
return status;
return wait_for_thread_etc(thread, 0, 0, _returnCode);
}
@ -1959,8 +1964,7 @@ setrlimit(int resource, const struct rlimit * rlp)
}
// #pragma mark -
// Calls from userland (with extra address checks)
// #pragma mark - syscalls
void
@ -2113,7 +2117,7 @@ _user_wait_for_thread(thread_id id, status_t *userReturnCode)
if (userReturnCode != NULL && !IS_USER_ADDRESS(userReturnCode))
return B_BAD_ADDRESS;
status = wait_for_thread(id, &returnCode);
status = wait_for_thread_etc(id, B_CAN_INTERRUPT, 0, &returnCode);
if (status == B_OK && userReturnCode != NULL
&& user_memcpy(userReturnCode, &returnCode, sizeof(status_t)) < B_OK)