* 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:
parent
f8f104b2e1
commit
33a9adb376
@ -61,6 +61,8 @@ thread_id peek_next_thread_id(void);
|
|||||||
|
|
||||||
thread_id spawn_kernel_thread_etc(thread_func, const char *name, int32 priority,
|
thread_id spawn_kernel_thread_etc(thread_func, const char *name, int32 priority,
|
||||||
void *args, team_id team, thread_id threadID);
|
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
|
// used in syscalls.c
|
||||||
status_t _user_set_thread_priority(thread_id thread, int32 newPriority);
|
status_t _user_set_thread_priority(thread_id thread, int32 newPriority);
|
||||||
|
@ -1164,8 +1164,7 @@ thread_at_kernel_exit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark - private kernel API
|
||||||
// private kernel exported functions
|
|
||||||
|
|
||||||
|
|
||||||
/** Insert a thread to the tail of a queue
|
/** 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
|
int32
|
||||||
thread_max_threads(void)
|
thread_max_threads(void)
|
||||||
{
|
{
|
||||||
@ -1415,8 +1474,7 @@ thread_per_cpu_init(int32 cpuNum)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark - public kernel API
|
||||||
// public kernel exported functions
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1841,62 +1899,9 @@ snooze_until(bigtime_t timeout, int timebase)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
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;
|
return wait_for_thread_etc(thread, 0, 0, _returnCode);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1959,8 +1964,7 @@ setrlimit(int resource, const struct rlimit * rlp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark - syscalls
|
||||||
// Calls from userland (with extra address checks)
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2113,7 +2117,7 @@ _user_wait_for_thread(thread_id id, status_t *userReturnCode)
|
|||||||
if (userReturnCode != NULL && !IS_USER_ADDRESS(userReturnCode))
|
if (userReturnCode != NULL && !IS_USER_ADDRESS(userReturnCode))
|
||||||
return B_BAD_ADDRESS;
|
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
|
if (status == B_OK && userReturnCode != NULL
|
||||||
&& user_memcpy(userReturnCode, &returnCode, sizeof(status_t)) < B_OK)
|
&& user_memcpy(userReturnCode, &returnCode, sizeof(status_t)) < B_OK)
|
||||||
|
Loading…
Reference in New Issue
Block a user