* For each userland team the kernel creates an area in the userland
address space that is fully locked and marked B_KERNEL_AREA. It can thus be accessed by the kernel without additional checks. * For each userland thread we do create a user_thread structure in that area. The structure is accessible from userland via TLS, using the private get_user_thread() function. * Introduced private userland functions [un]defer_signals(). They can be used to cheaply disable/re-enable signal delivery. They use the user_thread::defer_signals/pending_signals fields which are checked/updated by the kernel. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25451 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -32,7 +32,8 @@
|
|||||||
#define USER_SIZE (KERNEL_BASE - 0x10000)
|
#define USER_SIZE (KERNEL_BASE - 0x10000)
|
||||||
#define USER_TOP (USER_BASE + USER_SIZE)
|
#define USER_TOP (USER_BASE + USER_SIZE)
|
||||||
|
|
||||||
#define USER_STACK_REGION 0x70000000
|
#define KERNEL_USER_DATA_BASE 0x6fff0000
|
||||||
#define USER_STACK_REGION_SIZE (USER_TOP - USER_STACK_REGION)
|
#define USER_STACK_REGION 0x70000000
|
||||||
|
#define USER_STACK_REGION_SIZE (USER_TOP - USER_STACK_REGION)
|
||||||
|
|
||||||
#endif /* _KERNEL_ARCH_x86_KERNEL_H */
|
#endif /* _KERNEL_ARCH_x86_KERNEL_H */
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ status_t start_watching_team(team_id team, void (*hook)(team_id, void *),
|
|||||||
status_t stop_watching_team(team_id team, void (*hook)(team_id, void *),
|
status_t stop_watching_team(team_id team, void (*hook)(team_id, void *),
|
||||||
void *data);
|
void *data);
|
||||||
|
|
||||||
|
struct user_thread* team_allocate_user_thread(struct team* team);
|
||||||
|
void team_free_user_thread(struct thread* thread);
|
||||||
|
|
||||||
// used in syscalls.c
|
// used in syscalls.c
|
||||||
thread_id _user_load_image(int32 argCount, const char **args, int32 envCount,
|
thread_id _user_load_image(int32 argCount, const char **args, int32 envCount,
|
||||||
const char **env, int32 priority, uint32 flags,
|
const char **env, int32 priority, uint32 flags,
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ enum {
|
|||||||
struct image; // defined in image.c
|
struct image; // defined in image.c
|
||||||
struct realtime_sem_context; // defined in realtime_sem.cpp
|
struct realtime_sem_context; // defined in realtime_sem.cpp
|
||||||
struct select_info;
|
struct select_info;
|
||||||
|
struct user_thread; // defined in libroot/user_thread.h
|
||||||
|
|
||||||
struct death_entry {
|
struct death_entry {
|
||||||
struct list_link link;
|
struct list_link link;
|
||||||
@@ -165,6 +166,11 @@ struct team_dead_children : team_job_control_children {
|
|||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
|
||||||
|
struct free_user_thread {
|
||||||
|
struct free_user_thread* next;
|
||||||
|
struct user_thread* thread;
|
||||||
|
};
|
||||||
|
|
||||||
struct team {
|
struct team {
|
||||||
struct team *next; // next in hash
|
struct team *next; // next in hash
|
||||||
struct team *siblings_next;
|
struct team *siblings_next;
|
||||||
@@ -199,6 +205,12 @@ struct team {
|
|||||||
struct list watcher_list;
|
struct list watcher_list;
|
||||||
struct arch_team arch_info;
|
struct arch_team arch_info;
|
||||||
|
|
||||||
|
addr_t user_data;
|
||||||
|
area_id user_data_area;
|
||||||
|
size_t user_data_size;
|
||||||
|
size_t used_user_data;
|
||||||
|
struct free_user_thread* free_user_threads;
|
||||||
|
|
||||||
struct team_debug_info debug_info;
|
struct team_debug_info debug_info;
|
||||||
|
|
||||||
bigtime_t dead_threads_kernel_time;
|
bigtime_t dead_threads_kernel_time;
|
||||||
@@ -239,13 +251,15 @@ struct thread {
|
|||||||
size_t signal_stack_size;
|
size_t signal_stack_size;
|
||||||
bool signal_stack_enabled;
|
bool signal_stack_enabled;
|
||||||
|
|
||||||
|
bool in_kernel;
|
||||||
|
bool was_yielded;
|
||||||
|
|
||||||
|
struct user_thread* user_thread;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8 parameters[32];
|
uint8 parameters[32];
|
||||||
} syscall_restart;
|
} syscall_restart;
|
||||||
|
|
||||||
bool in_kernel;
|
|
||||||
bool was_yielded;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
status_t status; // current wait status
|
status_t status; // current wait status
|
||||||
uint32 flags; // interrupable flags
|
uint32 flags; // interrupable flags
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ enum {
|
|||||||
TLS_THREAD_ID_SLOT,
|
TLS_THREAD_ID_SLOT,
|
||||||
TLS_ERRNO_SLOT,
|
TLS_ERRNO_SLOT,
|
||||||
TLS_ON_EXIT_THREAD_SLOT,
|
TLS_ON_EXIT_THREAD_SLOT,
|
||||||
|
TLS_USER_THREAD_SLOT,
|
||||||
|
|
||||||
// Note: these entries can safely be changed between
|
// Note: these entries can safely be changed between
|
||||||
// releases; 3rd party code always calls tls_allocate()
|
// releases; 3rd party code always calls tls_allocate()
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _LIBROOT_USER_THREAD_H
|
||||||
|
#define _LIBROOT_USER_THREAD_H
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
#include <TLS.h>
|
||||||
|
|
||||||
|
#include <tls.h> /* kernel header */
|
||||||
|
|
||||||
|
|
||||||
|
struct user_thread {
|
||||||
|
int32 defer_signals; // counter; 0 == signals allowed
|
||||||
|
uint32 pending_signals; // signals that are pending, when
|
||||||
|
// signals are deferred
|
||||||
|
status_t wait_status;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static inline user_thread*
|
||||||
|
get_user_thread()
|
||||||
|
{
|
||||||
|
return (user_thread*)tls_get(TLS_USER_THREAD_SLOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void inline
|
||||||
|
defer_signals()
|
||||||
|
{
|
||||||
|
get_user_thread()->defer_signals++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void inline
|
||||||
|
undefer_signals()
|
||||||
|
{
|
||||||
|
user_thread* thread = get_user_thread();
|
||||||
|
if (--thread->defer_signals == 0 && thread->pending_signals != 0) {
|
||||||
|
// signals shall no longer be deferred -- call a dummy syscall to handle
|
||||||
|
// the pending ones
|
||||||
|
is_computer_on();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _LIBROOT_USER_THREAD_H */
|
||||||
@@ -10,6 +10,7 @@ SubDir HAIKU_TOP src system kernel ;
|
|||||||
SubDirC++Flags $(defines) ;
|
SubDirC++Flags $(defines) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UsePrivateHeaders libroot ;
|
||||||
UsePrivateHeaders shared ;
|
UsePrivateHeaders shared ;
|
||||||
UsePrivateHeaders runtime_loader ;
|
UsePrivateHeaders runtime_loader ;
|
||||||
|
|
||||||
|
|||||||
@@ -309,15 +309,17 @@ arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void),
|
|||||||
status_t
|
status_t
|
||||||
arch_thread_init_tls(struct thread *thread)
|
arch_thread_init_tls(struct thread *thread)
|
||||||
{
|
{
|
||||||
uint32 tls[TLS_THREAD_ID_SLOT + 1];
|
uint32 tls[TLS_USER_THREAD_SLOT + 1];
|
||||||
int32 i;
|
int32 i;
|
||||||
|
|
||||||
thread->user_local_storage = thread->user_stack_base
|
thread->user_local_storage = thread->user_stack_base
|
||||||
+ thread->user_stack_size;
|
+ thread->user_stack_size;
|
||||||
|
|
||||||
// initialize default TLS fields
|
// initialize default TLS fields
|
||||||
|
memset(tls, 0, sizeof(tls));
|
||||||
tls[TLS_BASE_ADDRESS_SLOT] = thread->user_local_storage;
|
tls[TLS_BASE_ADDRESS_SLOT] = thread->user_local_storage;
|
||||||
tls[TLS_THREAD_ID_SLOT] = thread->id;
|
tls[TLS_THREAD_ID_SLOT] = thread->id;
|
||||||
|
tls[TLS_USER_THREAD_SLOT] = (addr_t)thread->user_thread;
|
||||||
|
|
||||||
return user_memcpy((void *)thread->user_local_storage, tls, sizeof(tls));
|
return user_memcpy((void *)thread->user_local_storage, tls, sizeof(tls));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <tracing.h>
|
#include <tracing.h>
|
||||||
#include <user_debugger.h>
|
#include <user_debugger.h>
|
||||||
|
#include <user_thread.h>
|
||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -42,6 +43,11 @@
|
|||||||
#define DEFAULT_IGNORE_SIGNALS \
|
#define DEFAULT_IGNORE_SIGNALS \
|
||||||
(SIGNAL_TO_MASK(SIGCHLD) | SIGNAL_TO_MASK(SIGWINCH) \
|
(SIGNAL_TO_MASK(SIGCHLD) | SIGNAL_TO_MASK(SIGWINCH) \
|
||||||
| SIGNAL_TO_MASK(SIGCONT))
|
| SIGNAL_TO_MASK(SIGCONT))
|
||||||
|
#define NON_DEFERRABLE_SIGNALS \
|
||||||
|
(KILL_SIGNALS \
|
||||||
|
| SIGNAL_TO_MASK(SIGILL) \
|
||||||
|
| SIGNAL_TO_MASK(SIGFPE) \
|
||||||
|
| SIGNAL_TO_MASK(SIGSEGV))
|
||||||
|
|
||||||
|
|
||||||
const char * const sigstr[NSIG] = {
|
const char * const sigstr[NSIG] = {
|
||||||
@@ -270,6 +276,14 @@ handle_signals(struct thread *thread)
|
|||||||
if (signalMask == 0)
|
if (signalMask == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (thread->user_thread->defer_signals > 0
|
||||||
|
&& (signalMask & NON_DEFERRABLE_SIGNALS) == 0) {
|
||||||
|
thread->user_thread->pending_signals = signalMask;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread->user_thread->pending_signals = 0;
|
||||||
|
|
||||||
bool restart = (atomic_and(&thread->flags,
|
bool restart = (atomic_and(&thread->flags,
|
||||||
~THREAD_FLAGS_DONT_RESTART_SYSCALL)
|
~THREAD_FLAGS_DONT_RESTART_SYSCALL)
|
||||||
& THREAD_FLAGS_DONT_RESTART_SYSCALL) == 0;
|
& THREAD_FLAGS_DONT_RESTART_SYSCALL) == 0;
|
||||||
|
|||||||
+152
-2
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, [email protected].
|
||||||
* Copyright 2002-2008, Axel Dörfler, [email protected].
|
* Copyright 2002-2008, Axel Dörfler, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
#include <tls.h>
|
#include <tls.h>
|
||||||
#include <tracing.h>
|
#include <tracing.h>
|
||||||
#include <user_runtime.h>
|
#include <user_runtime.h>
|
||||||
|
#include <user_thread.h>
|
||||||
#include <usergroup.h>
|
#include <usergroup.h>
|
||||||
#include <vfs.h>
|
#include <vfs.h>
|
||||||
#include <vm.h>
|
#include <vm.h>
|
||||||
@@ -69,6 +71,7 @@ struct fork_arg {
|
|||||||
size_t user_stack_size;
|
size_t user_stack_size;
|
||||||
addr_t user_local_storage;
|
addr_t user_local_storage;
|
||||||
sigset_t sig_block_mask;
|
sigset_t sig_block_mask;
|
||||||
|
struct user_thread* user_thread;
|
||||||
|
|
||||||
struct arch_fork_arg arch_info;
|
struct arch_fork_arg arch_info;
|
||||||
};
|
};
|
||||||
@@ -830,6 +833,11 @@ create_team_struct(const char *name, bool kernel)
|
|||||||
team->state = TEAM_STATE_BIRTH;
|
team->state = TEAM_STATE_BIRTH;
|
||||||
team->flags = 0;
|
team->flags = 0;
|
||||||
team->death_sem = -1;
|
team->death_sem = -1;
|
||||||
|
team->user_data_area = -1;
|
||||||
|
team->user_data = 0;
|
||||||
|
team->used_user_data = 0;
|
||||||
|
team->user_data_size = 0;
|
||||||
|
team->free_user_threads = NULL;
|
||||||
|
|
||||||
team->supplementary_groups = NULL;
|
team->supplementary_groups = NULL;
|
||||||
team->supplementary_group_count = 0;
|
team->supplementary_group_count = 0;
|
||||||
@@ -911,6 +919,11 @@ delete_team_struct(struct team *team)
|
|||||||
while (job_control_entry* entry = team->dead_children->entries.RemoveHead())
|
while (job_control_entry* entry = team->dead_children->entries.RemoveHead())
|
||||||
delete entry;
|
delete entry;
|
||||||
|
|
||||||
|
while (free_user_thread* entry = team->free_user_threads) {
|
||||||
|
team->free_user_threads = entry->next;
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
malloc_referenced_release(team->supplementary_groups);
|
malloc_referenced_release(team->supplementary_groups);
|
||||||
|
|
||||||
delete team->job_control_entry;
|
delete team->job_control_entry;
|
||||||
@@ -935,6 +948,42 @@ get_arguments_data_size(char **args, int32 argc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
create_team_user_data(struct team* team)
|
||||||
|
{
|
||||||
|
void* address = (void*)KERNEL_USER_DATA_BASE;
|
||||||
|
size_t size = 4 * B_PAGE_SIZE;
|
||||||
|
team->user_data_area = create_area_etc(team, "user area", &address,
|
||||||
|
B_BASE_ADDRESS, size, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
|
||||||
|
if (team->user_data_area < 0)
|
||||||
|
return team->user_data_area;
|
||||||
|
|
||||||
|
team->user_data = (addr_t)address;
|
||||||
|
team->used_user_data = 0;
|
||||||
|
team->user_data_size = size;
|
||||||
|
team->free_user_threads = NULL;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_team_user_data(struct team* team)
|
||||||
|
{
|
||||||
|
if (team->user_data_area >= 0) {
|
||||||
|
delete_area_etc(team, team->user_data_area);
|
||||||
|
team->user_data = 0;
|
||||||
|
team->used_user_data = 0;
|
||||||
|
team->user_data_size = 0;
|
||||||
|
team->user_data_area = -1;
|
||||||
|
while (free_user_thread* entry = team->free_user_threads) {
|
||||||
|
team->free_user_threads = entry->next;
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_team_arg(struct team_arg *teamArg)
|
free_team_arg(struct team_arg *teamArg)
|
||||||
{
|
{
|
||||||
@@ -1004,6 +1053,9 @@ team_create_thread_start(void *args)
|
|||||||
|
|
||||||
TRACE(("team_create_thread_start: entry thread %ld\n", t->id));
|
TRACE(("team_create_thread_start: entry thread %ld\n", t->id));
|
||||||
|
|
||||||
|
// get a user thread for the main thread
|
||||||
|
t->user_thread = team_allocate_user_thread(team);
|
||||||
|
|
||||||
// create an initial primary stack area
|
// create an initial primary stack area
|
||||||
|
|
||||||
// Main stack area layout is currently as follows (starting from 0):
|
// Main stack area layout is currently as follows (starting from 0):
|
||||||
@@ -1216,13 +1268,18 @@ load_image_etc(int32 argCount, char * const *args, int32 envCount,
|
|||||||
else
|
else
|
||||||
threadName = args[0];
|
threadName = args[0];
|
||||||
|
|
||||||
|
// create the user data area
|
||||||
|
status = create_team_user_data(team);
|
||||||
|
if (status != B_OK)
|
||||||
|
goto err4;
|
||||||
|
|
||||||
// Create a kernel thread, but under the context of the new team
|
// Create a kernel thread, but under the context of the new team
|
||||||
// The new thread will take over ownership of teamArgs
|
// The new thread will take over ownership of teamArgs
|
||||||
thread = spawn_kernel_thread_etc(team_create_thread_start, threadName,
|
thread = spawn_kernel_thread_etc(team_create_thread_start, threadName,
|
||||||
B_NORMAL_PRIORITY, teamArgs, team->id, team->id);
|
B_NORMAL_PRIORITY, teamArgs, team->id, team->id);
|
||||||
if (thread < 0) {
|
if (thread < 0) {
|
||||||
status = thread;
|
status = thread;
|
||||||
goto err4;
|
goto err5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for the loader of the new team to finish its work
|
// wait for the loader of the new team to finish its work
|
||||||
@@ -1264,6 +1321,8 @@ load_image_etc(int32 argCount, char * const *args, int32 envCount,
|
|||||||
|
|
||||||
return thread;
|
return thread;
|
||||||
|
|
||||||
|
err5:
|
||||||
|
delete_team_user_data(team);
|
||||||
err4:
|
err4:
|
||||||
vm_put_address_space(team->address_space);
|
vm_put_address_space(team->address_space);
|
||||||
err3:
|
err3:
|
||||||
@@ -1362,6 +1421,7 @@ exec_team(const char *path, int32 argCount, char * const *args,
|
|||||||
|
|
||||||
user_debug_prepare_for_exec();
|
user_debug_prepare_for_exec();
|
||||||
|
|
||||||
|
delete_team_user_data(team);
|
||||||
vm_delete_areas(team->address_space);
|
vm_delete_areas(team->address_space);
|
||||||
delete_owned_ports(team->id);
|
delete_owned_ports(team->id);
|
||||||
sem_delete_owned_sems(team->id);
|
sem_delete_owned_sems(team->id);
|
||||||
@@ -1370,6 +1430,14 @@ exec_team(const char *path, int32 argCount, char * const *args,
|
|||||||
delete_realtime_sem_context(team->realtime_sem_context);
|
delete_realtime_sem_context(team->realtime_sem_context);
|
||||||
team->realtime_sem_context = NULL;
|
team->realtime_sem_context = NULL;
|
||||||
|
|
||||||
|
status = create_team_user_data(team);
|
||||||
|
if (status != B_OK) {
|
||||||
|
// creating the user data failed -- we're toast
|
||||||
|
// TODO: We should better keep the old user area in the first place.
|
||||||
|
exit_thread(status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
user_debug_finish_after_exec();
|
user_debug_finish_after_exec();
|
||||||
|
|
||||||
// rename the team
|
// rename the team
|
||||||
@@ -1422,6 +1490,7 @@ fork_team_thread_start(void *_args)
|
|||||||
thread->user_stack_size = forkArgs->user_stack_size;
|
thread->user_stack_size = forkArgs->user_stack_size;
|
||||||
thread->user_local_storage = forkArgs->user_local_storage;
|
thread->user_local_storage = forkArgs->user_local_storage;
|
||||||
thread->sig_block_mask = forkArgs->sig_block_mask;
|
thread->sig_block_mask = forkArgs->sig_block_mask;
|
||||||
|
thread->user_thread = forkArgs->user_thread;
|
||||||
|
|
||||||
arch_thread_init_tls(thread);
|
arch_thread_init_tls(thread);
|
||||||
|
|
||||||
@@ -1509,6 +1578,8 @@ fork_team(void)
|
|||||||
// ToDo: should be able to handle stack areas differently (ie. don't have them copy-on-write)
|
// ToDo: should be able to handle stack areas differently (ie. don't have them copy-on-write)
|
||||||
// ToDo: all stacks of other threads than the current one could be left out
|
// ToDo: all stacks of other threads than the current one could be left out
|
||||||
|
|
||||||
|
forkArgs->user_thread = NULL;
|
||||||
|
|
||||||
cookie = 0;
|
cookie = 0;
|
||||||
while (get_next_area_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
|
while (get_next_area_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
|
||||||
void *address;
|
void *address;
|
||||||
@@ -1519,13 +1590,30 @@ fork_team(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.area == parentThread->user_stack_area)
|
if (info.area == parentThread->user_stack_area) {
|
||||||
forkArgs->user_stack_area = area;
|
forkArgs->user_stack_area = area;
|
||||||
|
} else if (info.area == parentTeam->user_data_area) {
|
||||||
|
team->user_data = (addr_t)address;
|
||||||
|
team->used_user_data = 0;
|
||||||
|
team->user_data_size = info.size;
|
||||||
|
team->user_data_area = area;
|
||||||
|
team->free_user_threads = NULL;
|
||||||
|
forkArgs->user_thread = team_allocate_user_thread(team);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err4;
|
goto err4;
|
||||||
|
|
||||||
|
if (forkArgs->user_thread == NULL) {
|
||||||
|
#if KDEBUG
|
||||||
|
panic("user data area not found, parent area is %ld",
|
||||||
|
parentTeam->user_data_area);
|
||||||
|
#endif
|
||||||
|
status = B_ERROR;
|
||||||
|
goto err4;
|
||||||
|
}
|
||||||
|
|
||||||
forkArgs->user_stack_base = parentThread->user_stack_base;
|
forkArgs->user_stack_base = parentThread->user_stack_base;
|
||||||
forkArgs->user_stack_size = parentThread->user_stack_size;
|
forkArgs->user_stack_size = parentThread->user_stack_size;
|
||||||
forkArgs->user_local_storage = parentThread->user_local_storage;
|
forkArgs->user_local_storage = parentThread->user_local_storage;
|
||||||
@@ -2558,6 +2646,68 @@ stop_watching_team(team_id teamID, void (*hook)(team_id, void *), void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! The team lock must be held or the team must still be single threaded.
|
||||||
|
*/
|
||||||
|
struct user_thread*
|
||||||
|
team_allocate_user_thread(struct team* team)
|
||||||
|
{
|
||||||
|
if (team->user_data == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
user_thread* thread = NULL;
|
||||||
|
|
||||||
|
// take an entry from the free list, if any
|
||||||
|
if (struct free_user_thread* entry = team->free_user_threads) {
|
||||||
|
thread = entry->thread;
|
||||||
|
team->free_user_threads = entry->next;
|
||||||
|
deferred_free(entry);
|
||||||
|
return thread;
|
||||||
|
} else {
|
||||||
|
// enough space left?
|
||||||
|
size_t needed = _ALIGN(sizeof(user_thread));
|
||||||
|
if (team->user_data_size - team->used_user_data < needed)
|
||||||
|
return NULL;
|
||||||
|
// TODO: This imposes a per team thread limit! We should resize the
|
||||||
|
// area, if necessary. That's problematic at this point, though, since
|
||||||
|
// we've got the team lock.
|
||||||
|
|
||||||
|
thread = (user_thread*)(team->user_data + team->used_user_data);
|
||||||
|
team->used_user_data += needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread->defer_signals = 0;
|
||||||
|
thread->pending_signals = 0;
|
||||||
|
thread->wait_status = B_OK;
|
||||||
|
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! The team lock must not be held. \a thread must be the current thread.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
team_free_user_thread(struct thread* thread)
|
||||||
|
{
|
||||||
|
user_thread* userThread = thread->user_thread;
|
||||||
|
if (userThread == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// create a free list entry
|
||||||
|
free_user_thread* entry
|
||||||
|
= (free_user_thread*)malloc(sizeof(free_user_thread));
|
||||||
|
if (entry == NULL) {
|
||||||
|
// we have to leak the user thread :-/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InterruptsSpinLocker _(team_spinlock);
|
||||||
|
|
||||||
|
entry->thread = userThread;
|
||||||
|
entry->next = thread->team->free_user_threads;
|
||||||
|
thread->team->free_user_threads = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - Public kernel API
|
// #pragma mark - Public kernel API
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -444,7 +444,16 @@ create_thread(thread_creation_attributes& attributes, bool kernel)
|
|||||||
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(attributes.team);
|
team = team_get_team_struct_locked(attributes.team);
|
||||||
if (team != NULL && team->state != TEAM_STATE_DEATH) {
|
|
||||||
|
if (team == NULL || team->state == TEAM_STATE_DEATH)
|
||||||
|
abort = true;
|
||||||
|
|
||||||
|
if (!abort && !kernel) {
|
||||||
|
thread->user_thread = team_allocate_user_thread(team);
|
||||||
|
abort = thread->user_thread == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!abort) {
|
||||||
// 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
|
||||||
// debugger is installed for the team.
|
// debugger is installed for the team.
|
||||||
@@ -457,8 +466,7 @@ create_thread(thread_creation_attributes& attributes, bool kernel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
insert_thread_into_team(team, thread);
|
insert_thread_into_team(team, thread);
|
||||||
} else
|
}
|
||||||
abort = true;
|
|
||||||
|
|
||||||
RELEASE_TEAM_LOCK();
|
RELEASE_TEAM_LOCK();
|
||||||
if (abort) {
|
if (abort) {
|
||||||
@@ -1407,8 +1415,10 @@ thread_exit(void)
|
|||||||
if (team->main_thread == thread) {
|
if (team->main_thread == thread) {
|
||||||
// this was the main thread in this team, so we will delete that as well
|
// this was the main thread in this team, so we will delete that as well
|
||||||
deleteTeam = true;
|
deleteTeam = true;
|
||||||
} else
|
} else {
|
||||||
threadDeathEntry = (death_entry*)malloc(sizeof(death_entry));
|
threadDeathEntry = (death_entry*)malloc(sizeof(death_entry));
|
||||||
|
team_free_user_thread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
// remove this thread from the current team and add it to the kernel
|
// remove this thread from the current team and add it to the kernel
|
||||||
// put the thread into the kernel team until it dies
|
// put the thread into the kernel team until it dies
|
||||||
@@ -2937,4 +2947,3 @@ _user_setrlimit(int resource, const struct rlimit *userResourceLimit)
|
|||||||
|
|
||||||
return common_setrlimit(resource, &resourceLimit);
|
return common_setrlimit(resource, &resourceLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user