From 4c49f2056bbec860092e8c26520398b4121f8d1a Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 9 May 2008 01:32:36 +0000 Subject: [PATCH] * Changed _kern_spawn_thread() and create_thread(): Instead of individual arguments they get a single thread_creation_attributes structure now. * Added stack_address and stack_size to thread_creation_attributes, which allow to specify the stack size or the stack to be used for the new user thread. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25389 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/kernel.h | 2 + headers/private/kernel/syscalls.h | 5 +- headers/private/kernel/thread.h | 17 +++- src/system/kernel/thread.cpp | 130 +++++++++++++++++++++--------- src/system/libroot/os/thread.c | 14 +++- 5 files changed, 124 insertions(+), 44 deletions(-) diff --git a/headers/private/kernel/kernel.h b/headers/private/kernel/kernel.h index 5cb50d0d14..4eb4fbe343 100644 --- a/headers/private/kernel/kernel.h +++ b/headers/private/kernel/kernel.h @@ -37,6 +37,8 @@ /** Size of the stack given to teams in user space */ #define USER_MAIN_THREAD_STACK_SIZE (16 * 1024 * 1024) // 16 MB #define USER_STACK_SIZE (256 * 1024) // 256 kB +#define MIN_USER_STACK_SIZE (4 * 1024) // 4 KB +#define MAX_USER_STACK_SIZE (16 * 1024 * 1024) // 16 MB #define USER_STACK_GUARD_PAGES 4 // 16 kB /** Size of the environmental variables space for a process */ diff --git a/headers/private/kernel/syscalls.h b/headers/private/kernel/syscalls.h index 9637b7e100..3f431ed0b4 100644 --- a/headers/private/kernel/syscalls.h +++ b/headers/private/kernel/syscalls.h @@ -33,6 +33,7 @@ struct stat; struct disk_device_job_progress_info; struct partitionable_space_data; +struct thread_creation_attributes; struct user_disk_device_data; struct user_disk_device_job_info; struct user_disk_system_info; @@ -107,8 +108,8 @@ extern pid_t _kern_setpgid(pid_t process, pid_t group); extern pid_t _kern_setsid(void); extern status_t _kern_change_root(const char *path); -extern thread_id _kern_spawn_thread(int32 (*func)(thread_func, void *), - const char *name, int32 priority, void *data1, void *data2); +extern thread_id _kern_spawn_thread( + struct thread_creation_attributes* attributes); extern thread_id _kern_find_thread(const char *name); extern status_t _kern_suspend_thread(thread_id thread); extern status_t _kern_resume_thread(thread_id thread); diff --git a/headers/private/kernel/thread.h b/headers/private/kernel/thread.h index 90dd6d9e90..5959771a03 100644 --- a/headers/private/kernel/thread.h +++ b/headers/private/kernel/thread.h @@ -20,6 +20,21 @@ struct kernel_args; struct select_info; +struct thread_creation_attributes; + +struct thread_creation_attributes { + int32 (*entry)(thread_func, void *); + const char* name; + int32 priority; + void* args1; + void* args2; + void* stack_address; + size_t stack_size; + + // when calling kernel only + team_id team; + thread_id thread; +}; #ifdef __cplusplus @@ -89,7 +104,7 @@ status_t _user_rename_thread(thread_id thread, const char *name); status_t _user_suspend_thread(thread_id thread); status_t _user_resume_thread(thread_id thread); status_t _user_rename_thread(thread_id thread, const char *name); -thread_id _user_spawn_thread(thread_entry_func entry, const char *name, int32 priority, void *arg1, void *arg2); +thread_id _user_spawn_thread(struct thread_creation_attributes* attributes); status_t _user_wait_for_thread(thread_id id, status_t *_returnCode); status_t _user_snooze_etc(bigtime_t timeout, int timebase, uint32 flags); status_t _user_kill_thread(thread_id thread); diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 38af02dbb0..56bc0adf8d 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -364,8 +364,7 @@ _create_kernel_thread_kentry(void) \code < 0 \endcode a fresh one is allocated. */ static thread_id -create_thread(const char *name, team_id teamID, thread_entry_func entry, - void *args1, void *args2, int32 priority, bool kernel, thread_id threadID) +create_thread(thread_creation_attributes& attributes, bool kernel) { struct thread *thread, *currentThread; struct team *team; @@ -375,14 +374,16 @@ create_thread(const char *name, team_id teamID, thread_entry_func entry, bool abort = false; bool debugNewThread = false; - TRACE(("create_thread(%s, id = %ld, %s)\n", name, threadID, - kernel ? "kernel" : "user")); + TRACE(("create_thread(%s, id = %ld, %s)\n", attributes.name, + attributes.thread, kernel ? "kernel" : "user")); - thread = create_thread_struct(NULL, name, threadID, NULL); + thread = create_thread_struct(NULL, attributes.name, attributes.thread, + NULL); if (thread == NULL) return B_NO_MEMORY; - thread->priority = priority == -1 ? B_NORMAL_PRIORITY : priority; + thread->priority = attributes.priority == -1 + ? B_NORMAL_PRIORITY : attributes.priority; thread->next_priority = thread->priority; // ToDo: this could be dangerous in case someone calls resume_thread() on us thread->state = B_THREAD_SUSPENDED; @@ -391,7 +392,8 @@ create_thread(const char *name, team_id teamID, thread_entry_func entry, // init debug structure clear_thread_debug_info(&thread->debug_info, false); - snprintf(stack_name, B_OS_NAME_LENGTH, "%s_%ld_kstack", name, thread->id); + snprintf(stack_name, B_OS_NAME_LENGTH, "%s_%ld_kstack", attributes.name, + thread->id); thread->kernel_stack_area = create_area(stack_name, (void **)&thread->kernel_stack_base, B_ANY_KERNEL_ADDRESS, KERNEL_STACK_SIZE, B_FULL_LOCK, @@ -416,7 +418,7 @@ create_thread(const char *name, team_id teamID, thread_entry_func entry, // If the new thread belongs to the same team as the current thread, // it may inherit some of the thread debug flags. currentThread = thread_get_current_thread(); - if (currentThread && currentThread->team->id == teamID) { + if (currentThread && currentThread->team->id == attributes.team) { // inherit all user flags... int32 debugFlags = currentThread->debug_info.flags & B_THREAD_DEBUG_USER_FLAG_MASK; @@ -440,7 +442,7 @@ create_thread(const char *name, team_id teamID, thread_entry_func entry, GRAB_TEAM_LOCK(); // look at the team, make sure it's not being deleted - team = team_get_team_struct_locked(teamID); + team = team_get_team_struct_locked(attributes.team); if (team != NULL && team->state != TEAM_STATE_DEATH) { // Debug the new thread, if the parent thread required that (see above), // or the respective global team debug flag is set. But only, if a @@ -470,9 +472,9 @@ create_thread(const char *name, team_id teamID, thread_entry_func entry, return B_BAD_TEAM_ID; } - thread->args1 = args1; - thread->args2 = args2; - thread->entry = entry; + thread->args1 = attributes.args1; + thread->args2 = attributes.args2; + thread->entry = attributes.entry; status = thread->id; if (kernel) { @@ -485,22 +487,33 @@ create_thread(const char *name, team_id teamID, thread_entry_func entry, } else { // create user stack - // the stack will be between USER_STACK_REGION and the main thread stack area - // (the user stack of the main thread is created in team_create_team()) - thread->user_stack_base = USER_STACK_REGION; - thread->user_stack_size = USER_STACK_SIZE; + // the stack will be between USER_STACK_REGION and the main thread stack + // area (the user stack of the main thread is created in + // team_create_team()) + if (attributes.stack_address == NULL) { + thread->user_stack_base = USER_STACK_REGION; + if (attributes.stack_size <= 0) + thread->user_stack_size = USER_STACK_SIZE; + else + thread->user_stack_size = PAGE_ALIGN(attributes.stack_size); - snprintf(stack_name, B_OS_NAME_LENGTH, "%s_%ld_stack", name, thread->id); - thread->user_stack_area = create_area_etc(team, stack_name, - (void **)&thread->user_stack_base, B_BASE_ADDRESS, - thread->user_stack_size + TLS_SIZE, B_NO_LOCK, - B_READ_AREA | B_WRITE_AREA | B_STACK_AREA); - if (thread->user_stack_area < B_OK - || arch_thread_init_tls(thread) < B_OK) { - // great, we have a fully running thread without a (usable) stack - dprintf("create_thread: unable to create proper user stack!\n"); - status = thread->user_stack_area; - kill_thread(thread->id); + snprintf(stack_name, B_OS_NAME_LENGTH, "%s_%ld_stack", + attributes.name, thread->id); + thread->user_stack_area = create_area_etc(team, stack_name, + (void **)&thread->user_stack_base, B_BASE_ADDRESS, + thread->user_stack_size + TLS_SIZE, B_NO_LOCK, + B_READ_AREA | B_WRITE_AREA | B_STACK_AREA); + if (thread->user_stack_area < B_OK + || arch_thread_init_tls(thread) < B_OK) { + // great, we have a fully running thread without a (usable) + // stack + dprintf("create_thread: unable to create proper user stack!\n"); + status = thread->user_stack_area; + kill_thread(thread->id); + } + } else { + thread->user_stack_base = (addr_t)attributes.stack_address; + thread->user_stack_size = attributes.stack_size; } user_debug_update_new_thread_flags(thread->id); @@ -1829,8 +1842,18 @@ thread_id spawn_kernel_thread_etc(thread_func function, const char *name, int32 priority, void *arg, team_id team, thread_id threadID) { - return create_thread(name, team, (thread_entry_func)function, arg, NULL, - priority, true, threadID); + thread_creation_attributes attributes; + attributes.entry = (thread_entry_func)function; + attributes.name = name; + attributes.priority = priority; + attributes.args1 = arg; + attributes.args2 = NULL; + attributes.stack_address = NULL; + attributes.stack_size = 0; + attributes.team = team; + attributes.thread = threadID; + + return create_thread(attributes, true); } @@ -2593,8 +2616,18 @@ thread_id spawn_kernel_thread(thread_func function, const char *name, int32 priority, void *arg) { - return create_thread(name, team_get_kernel_team()->id, - (thread_entry_func)function, arg, NULL, priority, true, -1); + thread_creation_attributes attributes; + attributes.entry = (thread_entry_func)function; + attributes.name = name; + attributes.priority = priority; + attributes.args1 = arg; + attributes.args2 = NULL; + attributes.stack_address = NULL; + attributes.stack_size = 0; + attributes.team = team_get_kernel_team()->id; + attributes.thread = -1; + + return create_thread(attributes, true); } @@ -2677,22 +2710,39 @@ _user_set_thread_priority(thread_id thread, int32 newPriority) thread_id -_user_spawn_thread(int32 (*entry)(thread_func, void *), const char *userName, - int32 priority, void *data1, void *data2) +_user_spawn_thread(thread_creation_attributes* userAttributes) { + thread_creation_attributes attributes; + if (userAttributes == NULL || !IS_USER_ADDRESS(userAttributes) + || user_memcpy(&attributes, userAttributes, + sizeof(attributes)) != B_OK) { + return B_BAD_ADDRESS; + } + + if (attributes.stack_size != 0 + && (attributes.stack_size < MIN_USER_STACK_SIZE + || attributes.stack_size > MAX_USER_STACK_SIZE)) { + return B_BAD_VALUE; + } + char name[B_OS_NAME_LENGTH]; thread_id threadID; - if (!IS_USER_ADDRESS(entry) || entry == NULL - || (userName != NULL && (!IS_USER_ADDRESS(userName) - || user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK))) + if (!IS_USER_ADDRESS(attributes.entry) || attributes.entry == NULL + || attributes.stack_address != NULL + && !IS_USER_ADDRESS(attributes.stack_address) + || (attributes.name != NULL && (!IS_USER_ADDRESS(attributes.name) + || user_strlcpy(name, attributes.name, B_OS_NAME_LENGTH) < 0))) return B_BAD_ADDRESS; - threadID = create_thread(userName != NULL ? name : "user thread", - thread_get_current_thread()->team->id, entry, - data1, data2, priority, false, -1); + attributes.name = attributes.name != NULL ? name : "user thread"; + attributes.team = thread_get_current_thread()->team->id; + attributes.thread = -1; - user_debug_thread_created(threadID); + threadID = create_thread(attributes, false); + + if (threadID >= 0) + user_debug_thread_created(threadID); return threadID; } diff --git a/src/system/libroot/os/thread.c b/src/system/libroot/os/thread.c index e07424eb1d..6f41b679f7 100644 --- a/src/system/libroot/os/thread.c +++ b/src/system/libroot/os/thread.c @@ -9,6 +9,8 @@ #include #include +#include + #include "libroot_private.h" #include "tls.h" #include "syscalls.h" @@ -42,10 +44,20 @@ thread_entry(thread_func entry, void *data) thread_id spawn_thread(thread_func entry, const char *name, int32 priority, void *data) { + struct thread_creation_attributes attributes; + _single_threaded = false; // used for I/O locking - BeOS compatibility issue - return _kern_spawn_thread(thread_entry, name, priority, entry, data); + attributes.entry = &thread_entry; + attributes.name = name; + attributes.priority = priority; + attributes.args1 = entry; + attributes.args2 = data; + attributes.stack_address = NULL; + attributes.stack_size = 0; + + return _kern_spawn_thread(&attributes); }