diff --git a/headers/private/kernel/syscalls.h b/headers/private/kernel/syscalls.h index 3f431ed0b4..91c9b49cdb 100644 --- a/headers/private/kernel/syscalls.h +++ b/headers/private/kernel/syscalls.h @@ -130,6 +130,11 @@ extern status_t _kern_get_team_info(team_id id, team_info *info); extern status_t _kern_get_next_team_info(int32 *cookie, team_info *info); extern status_t _kern_get_team_usage_info(team_id team, int32 who, team_usage_info *info, size_t size); +extern status_t _kern_block_thread(uint32 flags, bigtime_t timeout); +extern status_t _kern_unblock_thread(thread_id thread, status_t status); +extern status_t _kern_unblock_threads(thread_id* threads, uint32 count, + status_t status); + // user/group functions extern gid_t _kern_getgid(bool effective); extern uid_t _kern_getuid(bool effective); diff --git a/headers/private/kernel/thread.h b/headers/private/kernel/thread.h index 5959771a03..3511d434b6 100644 --- a/headers/private/kernel/thread.h +++ b/headers/private/kernel/thread.h @@ -117,6 +117,11 @@ thread_id _user_find_thread(const char *name); status_t _user_get_thread_info(thread_id id, thread_info *info); status_t _user_get_next_thread_info(team_id team, int32 *cookie, thread_info *info); +status_t _user_block_thread(uint32 flags, bigtime_t timeout); +status_t _user_unblock_thread(thread_id thread, status_t status); +status_t _user_unblock_threads(thread_id* threads, uint32 count, + status_t status); + // ToDo: these don't belong here struct rlimit; int _user_getrlimit(int resource, struct rlimit * rlp); diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 148fcf78d6..2f9d5dc051 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -2309,6 +2310,23 @@ thread_block_with_timeout_locked(uint32 timeoutFlags, bigtime_t timeout) } +/*! Thread spinlock must be held. +*/ +static status_t +user_unblock_thread(thread_id threadID, status_t status) +{ + struct thread* thread = thread_get_thread_struct_locked(threadID); + if (thread == NULL) + return B_BAD_THREAD_ID; + if (thread->user_thread == NULL) + return B_NOT_ALLOWED; + + thread_unblock_locked(thread, status); + + return B_OK; +} + + // #pragma mark - public kernel API @@ -2903,7 +2921,61 @@ _user_receive_data(thread_id *_userSender, void *buffer, size_t bufferSize) } -// ToDo: the following two functions don't belong here +status_t +_user_block_thread(uint32 flags, bigtime_t timeout) +{ + syscall_restart_handle_timeout_pre(flags, timeout); + flags |= B_CAN_INTERRUPT; + + struct thread* thread = thread_get_current_thread(); + + InterruptsSpinLocker locker(thread_spinlock); + + // check, if already done + if (thread->user_thread->wait_status <= 0) + return thread->user_thread->wait_status; + + // nope, so wait + thread_prepare_to_block(thread, flags, THREAD_BLOCK_TYPE_OTHER, "user"); + status_t status = thread_block_with_timeout_locked(flags, timeout); + thread->user_thread->wait_status = status; + + return syscall_restart_handle_timeout_post(status, timeout); +} + + +status_t +_user_unblock_thread(thread_id threadID, status_t status) +{ + InterruptsSpinLocker locker(thread_spinlock); + return user_unblock_thread(threadID, status); +} + + +status_t +_user_unblock_threads(thread_id* userThreads, uint32 count, status_t status) +{ + enum { + MAX_USER_THREADS_TO_UNBLOCK = 128 + }; + + if (userThreads == NULL || !IS_USER_ADDRESS(userThreads)) + return B_BAD_ADDRESS; + if (count > MAX_USER_THREADS_TO_UNBLOCK) + return B_BAD_VALUE; + + thread_id threads[MAX_USER_THREADS_TO_UNBLOCK]; + if (user_memcpy(threads, userThreads, count * sizeof(thread_id)) != B_OK) + return B_BAD_ADDRESS; + + for (uint32 i = 0; i < count; i++) + user_unblock_thread(threads[i], status); + + return B_OK; +} + + +// TODO: the following two functions don't belong here int