* 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
This commit is contained in:
Ingo Weinhold 2008-05-09 01:32:36 +00:00
parent 6eea7aabb8
commit 4c49f2056b
5 changed files with 124 additions and 44 deletions

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -9,6 +9,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <thread.h>
#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);
}