* 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:
@@ -37,6 +37,8 @@
|
|||||||
/** Size of the stack given to teams in user space */
|
/** Size of the stack given to teams in user space */
|
||||||
#define USER_MAIN_THREAD_STACK_SIZE (16 * 1024 * 1024) // 16 MB
|
#define USER_MAIN_THREAD_STACK_SIZE (16 * 1024 * 1024) // 16 MB
|
||||||
#define USER_STACK_SIZE (256 * 1024) // 256 kB
|
#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
|
#define USER_STACK_GUARD_PAGES 4 // 16 kB
|
||||||
|
|
||||||
/** Size of the environmental variables space for a process */
|
/** Size of the environmental variables space for a process */
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ struct stat;
|
|||||||
|
|
||||||
struct disk_device_job_progress_info;
|
struct disk_device_job_progress_info;
|
||||||
struct partitionable_space_data;
|
struct partitionable_space_data;
|
||||||
|
struct thread_creation_attributes;
|
||||||
struct user_disk_device_data;
|
struct user_disk_device_data;
|
||||||
struct user_disk_device_job_info;
|
struct user_disk_device_job_info;
|
||||||
struct user_disk_system_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 pid_t _kern_setsid(void);
|
||||||
extern status_t _kern_change_root(const char *path);
|
extern status_t _kern_change_root(const char *path);
|
||||||
|
|
||||||
extern thread_id _kern_spawn_thread(int32 (*func)(thread_func, void *),
|
extern thread_id _kern_spawn_thread(
|
||||||
const char *name, int32 priority, void *data1, void *data2);
|
struct thread_creation_attributes* attributes);
|
||||||
extern thread_id _kern_find_thread(const char *name);
|
extern thread_id _kern_find_thread(const char *name);
|
||||||
extern status_t _kern_suspend_thread(thread_id thread);
|
extern status_t _kern_suspend_thread(thread_id thread);
|
||||||
extern status_t _kern_resume_thread(thread_id thread);
|
extern status_t _kern_resume_thread(thread_id thread);
|
||||||
|
|||||||
@@ -20,6 +20,21 @@
|
|||||||
|
|
||||||
struct kernel_args;
|
struct kernel_args;
|
||||||
struct select_info;
|
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
|
#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_suspend_thread(thread_id thread);
|
||||||
status_t _user_resume_thread(thread_id thread);
|
status_t _user_resume_thread(thread_id thread);
|
||||||
status_t _user_rename_thread(thread_id thread, const char *name);
|
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_wait_for_thread(thread_id id, status_t *_returnCode);
|
||||||
status_t _user_snooze_etc(bigtime_t timeout, int timebase, uint32 flags);
|
status_t _user_snooze_etc(bigtime_t timeout, int timebase, uint32 flags);
|
||||||
status_t _user_kill_thread(thread_id thread);
|
status_t _user_kill_thread(thread_id thread);
|
||||||
|
|||||||
@@ -364,8 +364,7 @@ _create_kernel_thread_kentry(void)
|
|||||||
\code < 0 \endcode a fresh one is allocated.
|
\code < 0 \endcode a fresh one is allocated.
|
||||||
*/
|
*/
|
||||||
static thread_id
|
static thread_id
|
||||||
create_thread(const char *name, team_id teamID, thread_entry_func entry,
|
create_thread(thread_creation_attributes& attributes, bool kernel)
|
||||||
void *args1, void *args2, int32 priority, bool kernel, thread_id threadID)
|
|
||||||
{
|
{
|
||||||
struct thread *thread, *currentThread;
|
struct thread *thread, *currentThread;
|
||||||
struct team *team;
|
struct team *team;
|
||||||
@@ -375,14 +374,16 @@ create_thread(const char *name, team_id teamID, thread_entry_func entry,
|
|||||||
bool abort = false;
|
bool abort = false;
|
||||||
bool debugNewThread = false;
|
bool debugNewThread = false;
|
||||||
|
|
||||||
TRACE(("create_thread(%s, id = %ld, %s)\n", name, threadID,
|
TRACE(("create_thread(%s, id = %ld, %s)\n", attributes.name,
|
||||||
kernel ? "kernel" : "user"));
|
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)
|
if (thread == NULL)
|
||||||
return B_NO_MEMORY;
|
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;
|
thread->next_priority = thread->priority;
|
||||||
// ToDo: this could be dangerous in case someone calls resume_thread() on us
|
// ToDo: this could be dangerous in case someone calls resume_thread() on us
|
||||||
thread->state = B_THREAD_SUSPENDED;
|
thread->state = B_THREAD_SUSPENDED;
|
||||||
@@ -391,7 +392,8 @@ create_thread(const char *name, team_id teamID, thread_entry_func entry,
|
|||||||
// init debug structure
|
// init debug structure
|
||||||
clear_thread_debug_info(&thread->debug_info, false);
|
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,
|
thread->kernel_stack_area = create_area(stack_name,
|
||||||
(void **)&thread->kernel_stack_base, B_ANY_KERNEL_ADDRESS,
|
(void **)&thread->kernel_stack_base, B_ANY_KERNEL_ADDRESS,
|
||||||
KERNEL_STACK_SIZE, B_FULL_LOCK,
|
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,
|
// If the new thread belongs to the same team as the current thread,
|
||||||
// it may inherit some of the thread debug flags.
|
// it may inherit some of the thread debug flags.
|
||||||
currentThread = thread_get_current_thread();
|
currentThread = thread_get_current_thread();
|
||||||
if (currentThread && currentThread->team->id == teamID) {
|
if (currentThread && currentThread->team->id == attributes.team) {
|
||||||
// inherit all user flags...
|
// inherit all user flags...
|
||||||
int32 debugFlags = currentThread->debug_info.flags
|
int32 debugFlags = currentThread->debug_info.flags
|
||||||
& B_THREAD_DEBUG_USER_FLAG_MASK;
|
& 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();
|
GRAB_TEAM_LOCK();
|
||||||
// look at the team, make sure it's not being deleted
|
// 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) {
|
if (team != NULL && team->state != TEAM_STATE_DEATH) {
|
||||||
// Debug the new thread, if the parent thread required that (see above),
|
// 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
|
// 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;
|
return B_BAD_TEAM_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
thread->args1 = args1;
|
thread->args1 = attributes.args1;
|
||||||
thread->args2 = args2;
|
thread->args2 = attributes.args2;
|
||||||
thread->entry = entry;
|
thread->entry = attributes.entry;
|
||||||
status = thread->id;
|
status = thread->id;
|
||||||
|
|
||||||
if (kernel) {
|
if (kernel) {
|
||||||
@@ -485,22 +487,33 @@ create_thread(const char *name, team_id teamID, thread_entry_func entry,
|
|||||||
} else {
|
} else {
|
||||||
// create user stack
|
// create user stack
|
||||||
|
|
||||||
// the stack will be between USER_STACK_REGION and the main thread stack area
|
// the stack will be between USER_STACK_REGION and the main thread stack
|
||||||
// (the user stack of the main thread is created in team_create_team())
|
// area (the user stack of the main thread is created in
|
||||||
thread->user_stack_base = USER_STACK_REGION;
|
// team_create_team())
|
||||||
thread->user_stack_size = USER_STACK_SIZE;
|
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);
|
snprintf(stack_name, B_OS_NAME_LENGTH, "%s_%ld_stack",
|
||||||
thread->user_stack_area = create_area_etc(team, stack_name,
|
attributes.name, thread->id);
|
||||||
(void **)&thread->user_stack_base, B_BASE_ADDRESS,
|
thread->user_stack_area = create_area_etc(team, stack_name,
|
||||||
thread->user_stack_size + TLS_SIZE, B_NO_LOCK,
|
(void **)&thread->user_stack_base, B_BASE_ADDRESS,
|
||||||
B_READ_AREA | B_WRITE_AREA | B_STACK_AREA);
|
thread->user_stack_size + TLS_SIZE, B_NO_LOCK,
|
||||||
if (thread->user_stack_area < B_OK
|
B_READ_AREA | B_WRITE_AREA | B_STACK_AREA);
|
||||||
|| arch_thread_init_tls(thread) < B_OK) {
|
if (thread->user_stack_area < B_OK
|
||||||
// great, we have a fully running thread without a (usable) stack
|
|| arch_thread_init_tls(thread) < B_OK) {
|
||||||
dprintf("create_thread: unable to create proper user stack!\n");
|
// great, we have a fully running thread without a (usable)
|
||||||
status = thread->user_stack_area;
|
// stack
|
||||||
kill_thread(thread->id);
|
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);
|
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,
|
spawn_kernel_thread_etc(thread_func function, const char *name, int32 priority,
|
||||||
void *arg, team_id team, thread_id threadID)
|
void *arg, team_id team, thread_id threadID)
|
||||||
{
|
{
|
||||||
return create_thread(name, team, (thread_entry_func)function, arg, NULL,
|
thread_creation_attributes attributes;
|
||||||
priority, true, threadID);
|
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,
|
spawn_kernel_thread(thread_func function, const char *name, int32 priority,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
return create_thread(name, team_get_kernel_team()->id,
|
thread_creation_attributes attributes;
|
||||||
(thread_entry_func)function, arg, NULL, priority, true, -1);
|
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
|
thread_id
|
||||||
_user_spawn_thread(int32 (*entry)(thread_func, void *), const char *userName,
|
_user_spawn_thread(thread_creation_attributes* userAttributes)
|
||||||
int32 priority, void *data1, void *data2)
|
|
||||||
{
|
{
|
||||||
|
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];
|
char name[B_OS_NAME_LENGTH];
|
||||||
thread_id threadID;
|
thread_id threadID;
|
||||||
|
|
||||||
if (!IS_USER_ADDRESS(entry) || entry == NULL
|
if (!IS_USER_ADDRESS(attributes.entry) || attributes.entry == NULL
|
||||||
|| (userName != NULL && (!IS_USER_ADDRESS(userName)
|
|| attributes.stack_address != NULL
|
||||||
|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)))
|
&& !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;
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
threadID = create_thread(userName != NULL ? name : "user thread",
|
attributes.name = attributes.name != NULL ? name : "user thread";
|
||||||
thread_get_current_thread()->team->id, entry,
|
attributes.team = thread_get_current_thread()->team->id;
|
||||||
data1, data2, priority, false, -1);
|
attributes.thread = -1;
|
||||||
|
|
||||||
user_debug_thread_created(threadID);
|
threadID = create_thread(attributes, false);
|
||||||
|
|
||||||
|
if (threadID >= 0)
|
||||||
|
user_debug_thread_created(threadID);
|
||||||
|
|
||||||
return threadID;
|
return threadID;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <thread.h>
|
||||||
|
|
||||||
#include "libroot_private.h"
|
#include "libroot_private.h"
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
#include "syscalls.h"
|
#include "syscalls.h"
|
||||||
@@ -42,10 +44,20 @@ thread_entry(thread_func entry, void *data)
|
|||||||
thread_id
|
thread_id
|
||||||
spawn_thread(thread_func entry, const char *name, int32 priority, void *data)
|
spawn_thread(thread_func entry, const char *name, int32 priority, void *data)
|
||||||
{
|
{
|
||||||
|
struct thread_creation_attributes attributes;
|
||||||
|
|
||||||
_single_threaded = false;
|
_single_threaded = false;
|
||||||
// used for I/O locking - BeOS compatibility issue
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user