Added exit_thread().

Changed thread_atkernel_exit() to look less broken - the way and when it's
called should still be investigated: NewOS looks a lot cleaner here.
create_thread() now creates the kernel stack upfront, so that it can easily
bail out of that fails. The user stack creation now makes use of B_BASE_ADDRESS
and is therefore a lot better and simpler. In case user stack creation failed,
it should now be able to handle that a lot more gracefully - but that hasn't
been tested yet...
Some cleanup.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7897 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2004-06-11 01:45:33 +00:00
parent 6e0526544a
commit 4a847f30c5

View File

@ -151,7 +151,7 @@ create_thread_struct(const char *name)
if (t == NULL) {
t = (struct thread *)malloc(sizeof(struct thread));
if (t == NULL)
goto err;
return NULL;
}
strlcpy(t->name, name, B_OS_NAME_LENGTH);
@ -185,20 +185,20 @@ create_thread_struct(const char *name)
sprintf(temp, "thread_0x%lx_retcode_sem", t->id);
t->return_code_sem = create_sem(0, temp);
if (t->return_code_sem < 0)
if (t->return_code_sem < B_OK)
goto err1;
sprintf(temp, "%s data write sem", t->name);
sprintf(temp, "%s send", t->name);
t->msg.write_sem = create_sem(1, temp);
if (t->msg.write_sem < 0)
if (t->msg.write_sem < B_OK)
goto err2;
sprintf(temp, "%s data read sem", t->name);
sprintf(temp, "%s receive", t->name);
t->msg.read_sem = create_sem(0, temp);
if (t->msg.read_sem < 0)
if (t->msg.read_sem < B_OK)
goto err3;
if (arch_thread_init_thread_struct(t) < 0)
if (arch_thread_init_thread_struct(t) < B_OK)
goto err4;
return t;
@ -210,28 +210,27 @@ err3:
err2:
delete_sem_etc(t->return_code_sem, -1, false);
err1:
// ToDo: put them in the dead queue instead?
free(t);
err:
return NULL;
}
static void
delete_thread_struct(struct thread *t)
delete_thread_struct(struct thread *thread)
{
if (t->return_code_sem >= 0)
delete_sem_etc(t->return_code_sem, -1, false);
if (t->msg.write_sem >= 0)
delete_sem_etc(t->msg.write_sem, -1, false);
if (t->msg.read_sem >= 0)
delete_sem_etc(t->msg.read_sem, -1, false);
free(t);
delete_sem_etc(thread->return_code_sem, -1, false);
delete_sem_etc(thread->msg.write_sem, -1, false);
delete_sem_etc(thread->msg.read_sem, -1, false);
// ToDo: put them in the dead queue instead?
free(thread);
}
/** Initializes the thread and jumps to its userspace entry point.
* This function is called at creation time of every user thread,
* but not for the team's main threads.
* but not for a team's main thread.
*/
static int
@ -240,12 +239,12 @@ _create_user_thread_kentry(void)
struct thread *thread = thread_get_current_thread();
// a signal may have been delivered here
// ToDo: this looks broken
// thread_atkernel_exit();
// start tracking kernel & user time
thread->last_time = system_time();
thread->last_time_type = KERNEL_TIME;
thread->in_kernel = false;
// jump to the entry point in user space
arch_thread_enter_uspace(thread, (addr_t)thread->entry, thread->args1, thread->args2);
@ -280,20 +279,32 @@ create_thread(const char *name, team_id teamID, thread_func entry, void *args1,
struct thread *t;
struct team *team;
cpu_status state;
char stack_name[64];
char stack_name[B_OS_NAME_LENGTH];
status_t status;
bool abort = false;
addr_t mainThreadStackBase = USER_STACK_REGION + USER_STACK_REGION_SIZE;
t = create_thread_struct(name);
if (t == NULL)
return ENOMEM;
return B_NO_MEMORY;
t->priority = priority == -1 ? B_NORMAL_PRIORITY : priority;
// ToDo: revisit this one - the thread might go to early to B_THREAD_SUSPENDED
// t->state = THREAD_STATE_BIRTH;
t->state = B_THREAD_SUSPENDED; // Is this right?
// ToDo: this could be dangerous in case someone calls resume_thread() on us
t->state = B_THREAD_SUSPENDED;
t->next_state = B_THREAD_SUSPENDED;
snprintf(stack_name, B_OS_NAME_LENGTH, "%s_%lx_kstack", name, t->id);
t->kernel_stack_region_id = create_area(stack_name, (void **)&t->kernel_stack_base,
B_ANY_KERNEL_ADDRESS, KSTACK_SIZE, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
if (t->kernel_stack_region_id < 0) {
// we're not yet part of a team, so we can just bail out
dprintf("create_thread: error creating kernel stack!\n");
status = t->kernel_stack_region_id;
delete_thread_struct(t);
return status;
}
state = disable_interrupts();
GRAB_THREAD_LOCK();
@ -309,9 +320,6 @@ create_thread(const char *name, team_id teamID, thread_func entry, void *args1,
else
abort = true;
if (!kernel && team->main_thread)
mainThreadStackBase = team->main_thread->user_stack_base;
RELEASE_TEAM_LOCK();
if (abort) {
GRAB_THREAD_LOCK();
@ -320,20 +328,15 @@ create_thread(const char *name, team_id teamID, thread_func entry, void *args1,
}
restore_interrupts(state);
if (abort) {
delete_area(t->kernel_stack_region_id);
delete_thread_struct(t);
return B_BAD_TEAM_ID;
}
sprintf(stack_name, "%s_kstack", name);
t->kernel_stack_region_id = create_area(stack_name, (void **)&t->kernel_stack_base,
B_ANY_KERNEL_ADDRESS, KSTACK_SIZE, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
if (t->kernel_stack_region_id < 0)
panic("_create_thread: error creating kernel stack!\n");
t->args1 = args1;
t->args2 = args2;
t->entry = entry;
status = t->id;
if (kernel) {
// this sets up an initial kthread stack that runs the entry
@ -344,32 +347,23 @@ create_thread(const char *name, team_id teamID, thread_func entry, void *args1,
} else {
// create user stack
// ToDo: make this better. For now just keep trying to create a stack
// until we find a spot.
// -> implement B_BASE_ADDRESS for create_area() and use that one!
// (we can then also eliminate the mainThreadStackBase variable)
// ToDo: should we move the stack creation to _create_user_thread_kentry()?
// 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())
t->user_stack_base = USER_STACK_REGION;
while (t->user_stack_base < mainThreadStackBase) {
sprintf(stack_name, "%s_stack%ld", team->name, t->id);
t->user_stack_region_id = create_area_etc(team, stack_name,
(void **)&t->user_stack_base, B_EXACT_ADDRESS,
snprintf(stack_name, B_OS_NAME_LENGTH, "%s_%lx_stack", name, t->id);
t->user_stack_region_id = create_area_etc(team, stack_name,
(void **)&t->user_stack_base, B_BASE_ADDRESS,
STACK_SIZE + TLS_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (t->user_stack_region_id >= 0)
break;
t->user_stack_base += STACK_SIZE + TLS_SIZE;
if (t->user_stack_region_id < 0) {
// great, we have a fully running thread without a stack
dprintf("create_thread: unable to create user stack!\n");
status = t->user_stack_region_id;
kill_thread(t->id);
} else {
// now that the TLS area is allocated, initialize TLS
arch_thread_init_tls(t);
}
if (t->user_stack_region_id < 0)
panic("_create_thread: unable to create user stack!\n");
// now that the TLS area is allocated, initialize TLS
arch_thread_init_tls(t);
// copy the user entry over to the args field in the thread struct
// the function this will call will immediately switch the thread into
@ -377,9 +371,7 @@ create_thread(const char *name, team_id teamID, thread_func entry, void *args1,
arch_thread_init_kthread_stack(t, &_create_user_thread_kentry, &thread_kthread_entry, &thread_kthread_exit);
}
t->state = B_THREAD_SUSPENDED;
return t->id;
return status;
}
@ -609,7 +601,7 @@ get_death_stack(uint32 *_stack)
static void
put_death_stack_and_reschedule(uint32 index)
{
TRACE(("put_death_stack...: passed %d\n", index));
TRACE(("put_death_stack...: passed %lu\n", index));
if (index >= sNumDeathStacks)
panic("put_death_stack: passed invalid stack index %d\n", index);
@ -890,32 +882,33 @@ void
thread_atkernel_exit(void)
{
cpu_status state;
int global_resched;
struct thread *t;
bigtime_t now;
TRACE(("thread_atkernel_exit: entry\n"));
// ToDo: this may be broken (when it is called, and what exactly should it do...)
t = thread_get_current_thread();
state = disable_interrupts();
GRAB_THREAD_LOCK();
global_resched = handle_signals(t, state);
if (handle_signals(t, state))
scheduler_reschedule();
// was: smp_send_broadcast_ici(SMP_MSG_RESCHEDULE, 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC);
t->in_kernel = false;
RELEASE_THREAD_LOCK();
// track kernel time
now = system_time();
t->kernel_time += now - t->last_time;
t->last_time = now;
t->last_time_type = USER_TIME;
RELEASE_THREAD_LOCK();
restore_interrupts(state);
if (global_resched)
smp_send_broadcast_ici(SMP_MSG_RESCHEDULE, 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC);
}
@ -1099,11 +1092,23 @@ spawn_kernel_thread_etc(thread_func function, const char *name, int32 priority,
// public kernel exported functions
void
exit_thread(status_t returnValue)
{
struct thread *thread = thread_get_current_thread();
thread->return_code = returnValue;
thread->return_flags = THREAD_RETURN_EXIT;
send_signal_etc(thread->id, SIGKILLTHR, B_DO_NOT_RESCHEDULE);
}
status_t
kill_thread(thread_id id)
{
status_t status = send_signal_etc(id, SIGKILLTHR, B_DO_NOT_RESCHEDULE);
if (status < 0)
if (status < B_OK)
return status;
if (id != thread_get_current_thread()->id)
@ -1603,14 +1608,9 @@ setrlimit(int resource, const struct rlimit * rlp)
void
_user_exit_thread(status_t return_value)
_user_exit_thread(status_t returnValue)
{
struct thread *thread = thread_get_current_thread();
thread->return_code = return_value;
thread->return_flags = THREAD_RETURN_EXIT;
send_signal_etc(thread->id, SIGKILLTHR, B_DO_NOT_RESCHEDULE);
exit_thread(returnValue);
}