fix joins & detaches

This commit is contained in:
flysand7 2023-09-06 20:37:30 +11:00
parent 00d284215c
commit 35f10c78b7
9 changed files with 89 additions and 31 deletions

View File

@ -2,7 +2,9 @@
bits 64
section .text
global _cia_start_thread
global _rt_thread_start
extern _rt_thread_finish
; flags, &stack[-2], &parent_tid, &child_tid, 0
@ -23,7 +25,7 @@ global _cia_start_thread
; 0 if returning as a parent
; 1 if returning as a child
; negative value if there was an error making the thread
_cia_start_thread:
_rt_thread_start:
mov r10, rcx
; Setup child stack
sub rsi, 24
@ -43,10 +45,9 @@ _cia_start_thread:
pop rax ; thread_fn
pop rdi ; ctx
call rax
; Make return value the first arg and call exit syscall
; Make return value the first arg and call thread finish routine
mov rdi, rax
mov rax, 60
syscall
call _rt_thread_finish
; Just to be sure...
hlt
.exit:

1
cia.c
View File

@ -3,7 +3,6 @@
// Base includes
#include <cia/def.h>
#include <cia/internal.h>
// Platform-dependent sources
#include _CIA_OS_CONF

View File

@ -11,13 +11,28 @@ struct Cia_CRT_Params {
void *tls_image_base;
};
// These control how the thread should behave once it's terminated
// if the main thread didn't call join nor detach, the thread
// would just wait until one of them is set.
// If the thread is joined,
// would signal main thread that it has finished and exit without
// cleaning up the resources (thrd_join does that for us)
// If the thread is detached, it would clear it's resources and exit
#define _CIA_THREAD_BEHAVIOUR_NOT_SET 0x0
#define _CIA_THREAD_BEHAVIOUR_JOIN 0x1
#define _CIA_THREAD_BEHAVIOUR_DETACH 0x2
#define _CIA_THREAD_BEHAVIOUR_FINISH 0x3
struct Cia_TCB typedef Cia_TCB;
struct Cia_TCB {
u64 thread_id;
u64 parent_id;
u64 pad0[3];
u64 stack_canary;
u64 pad1[2];
/* +0x00 */ u64 thread_id;
/* +0x08 */ u64 parent_id;
/* +0x10 */ u32 thread_behaviour; /* One of the CIA_THREAD_BEHAVIOR_* constants */
/* +0x14 */ u32 thread_finished;
/* +0x18 */ u32 pad0;
/* +0x1c */ i32 exit_code;
/* +0x20 */ u64 pad1;
/* +0x28 */ u64 stack_canary;
};

View File

@ -17,3 +17,5 @@ enum {
};
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
int thrd_join(thrd_t thr, int *out_exit_code);
int thrd_detach(thrd_t thr);

View File

@ -55,7 +55,7 @@ struct _RT_Thread {
};
static _RT_Status _rt_thread_current(_RT_Thread *thread);
static _RT_Status _rt_thread_create(_RT_Thread *thread, int (*thread_fn)(void *ctx), void *ctx);
static _RT_Status _rt_thread_join(_RT_Thread *thread);
static _RT_Status _rt_thread_join(_RT_Thread *thread, int *out_exit_code);
static _RT_Status _rt_thread_detach(_RT_Thread *thread);
static _RT_Status _rt_thread_terminate(_RT_Thread *thread);
static _RT_Status _rt_thread_sleep(u64 time);

View File

@ -5,6 +5,8 @@ static u64 cia_stack_size;
static u64 cia_tls_image_size;
static void *cia_tls_image_base;
#include <cia/internal.h>
#include <linux/futex.h>
#include <sys/mman.h>
#include <errno.h>

View File

@ -1,5 +1,5 @@
extern i64 _cia_start_thread(
extern i64 _rt_thread_start(
u64 flags,
void *stack_base,
int *parent_tid,
@ -33,6 +33,7 @@ static _RT_Status _rt_thread_create(_RT_Thread *thread, int (*thread_fn)(void *c
// Initialize the _RT_Thread handle, which would point to
// the TCB
thread->handle = tcb;
tcb->thread_finished = 0;
// Create the new thread
u64 flags = 0;
// flags |= CLONE_CHILD_CLEARTID;
@ -47,19 +48,52 @@ static _RT_Status _rt_thread_create(_RT_Thread *thread, int (*thread_fn)(void *c
int *parent_tid = (int *)&tcb->parent_id;
*child_tid = 1;
*parent_tid = 0;
i64 ret = _cia_start_thread(flags, stack, parent_tid, child_tid, 0, thread_fn, ctx);
i64 ret = _rt_thread_start(flags, stack, parent_tid, child_tid, 0, thread_fn, ctx);
if(ret < 0) {
return _RT_ERROR_GENERIC;
}
return _RT_STATUS_OK;
}
static _RT_Status _rt_thread_join(_RT_Thread *thread) {
return _RT_ERROR_NOT_IMPLEMENTED;
void _rt_thread_finish(int exit_code) {
Cia_TCB *tcb = (void *)((u64)__builtin_frame_address(0) & ~(cia_stack_size - 1));
// Wait until the main thread decides what to do with the child thread
while(tcb->thread_behaviour == _CIA_THREAD_BEHAVIOUR_NOT_SET) {
syscall(SYS_futex, &tcb->thread_behaviour, FUTEX_WAIT, _CIA_THREAD_BEHAVIOUR_NOT_SET, NULL, 0, 0);
}
if(tcb->thread_behaviour == _CIA_THREAD_BEHAVIOUR_JOIN) {
tcb->exit_code = exit_code;
// Idk if a memory barrier should be here, because we don't want the compiler
// to reorder these two lines. If that happens, and we get a spurious wake up
// after the thread_finished is set and before exit_code is set, the main thread
// will proceed to fetch an invalid exit code from the thread.
tcb->thread_finished = 1;
syscall(SYS_futex, &tcb->thread_finished, FUTEX_WAKE, 0, NULL, 0, 0);
sys_exit(exit_code);
}
else if(tcb->thread_behaviour == _CIA_THREAD_BEHAVIOUR_DETACH) {
// TODO: clean up the thread resources
sys_exit(exit_code);
}
}
static _RT_Status _rt_thread_join(_RT_Thread *thread, int *out_exit_code) {
Cia_TCB *tcb = thread->handle;
// Signal the thread that we want it to be joined
tcb->thread_behaviour = _CIA_THREAD_BEHAVIOUR_JOIN;
// Wait until the thread signals that it has completed the execution
while(tcb->thread_finished != 1) {
syscall(SYS_futex, &tcb->thread_finished, FUTEX_WAIT, 0, NULL, 0, 0);
}
// Set the exit code
*out_exit_code = tcb->exit_code;
return _RT_STATUS_OK;
}
static _RT_Status _rt_thread_detach(_RT_Thread *thread) {
return _RT_ERROR_NOT_IMPLEMENTED;
Cia_TCB *tcb = thread->handle;
tcb->thread_behaviour = _CIA_THREAD_BEHAVIOUR_DETACH;
return _RT_STATUS_OK;
}
static _RT_Status _rt_thread_terminate(_RT_Thread *thread) {

View File

@ -5,4 +5,20 @@ int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) {
return thrd_success;
}
return thrd_error;
}
}
int thrd_detach(thrd_t thr) {
_RT_Status status = _rt_thread_detach(&thr.thread);
if(status == _RT_STATUS_OK) {
return thrd_success;
}
return thrd_error;
}
int thrd_join(thrd_t thr, int *out_exit_code) {
_RT_Status status = _rt_thread_join(&thr.thread, out_exit_code);
if(status == _RT_STATUS_OK) {
return thrd_success;
}
return thrd_error;
}

View File

@ -36,7 +36,6 @@ static void print_int(i64 number) {
static Cia_Mutex g_print_mutex;
static Cia_Mutex g_mutex;
static volatile _Atomic i64 n_completed = 0;
static volatile i64 counter = 0;
int thrd_func(void *arg) {
@ -46,12 +45,6 @@ int thrd_func(void *arg) {
counter += 1;
cia_mutex_unlock(&g_mutex);
}
atomic_fetch_add(&n_completed, 1);
for(;;) {
if(n_completed == 2) {
break;
}
}
cia_mutex_lock(&g_print_mutex);
print_string("child thread: counter = ");
print_int(counter);
@ -76,12 +69,8 @@ int main() {
counter += 1;
cia_mutex_unlock(&g_mutex);
}
atomic_fetch_add(&n_completed, 1);
for(;;) {
if(n_completed == 2) {
break;
}
}
int exit_code;
thrd_join(thrd, &exit_code);
cia_mutex_lock(&g_print_mutex);
print_string("main thread: counter = ");
print_int(counter);