mirror of https://github.com/flysand7/ciabatta.git
fix joins & detaches
This commit is contained in:
parent
00d284215c
commit
35f10c78b7
|
@ -2,7 +2,9 @@
|
||||||
bits 64
|
bits 64
|
||||||
|
|
||||||
section .text
|
section .text
|
||||||
global _cia_start_thread
|
global _rt_thread_start
|
||||||
|
|
||||||
|
extern _rt_thread_finish
|
||||||
|
|
||||||
; flags, &stack[-2], &parent_tid, &child_tid, 0
|
; flags, &stack[-2], &parent_tid, &child_tid, 0
|
||||||
|
|
||||||
|
@ -23,7 +25,7 @@ global _cia_start_thread
|
||||||
; 0 if returning as a parent
|
; 0 if returning as a parent
|
||||||
; 1 if returning as a child
|
; 1 if returning as a child
|
||||||
; negative value if there was an error making the thread
|
; negative value if there was an error making the thread
|
||||||
_cia_start_thread:
|
_rt_thread_start:
|
||||||
mov r10, rcx
|
mov r10, rcx
|
||||||
; Setup child stack
|
; Setup child stack
|
||||||
sub rsi, 24
|
sub rsi, 24
|
||||||
|
@ -43,10 +45,9 @@ _cia_start_thread:
|
||||||
pop rax ; thread_fn
|
pop rax ; thread_fn
|
||||||
pop rdi ; ctx
|
pop rdi ; ctx
|
||||||
call rax
|
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 rdi, rax
|
||||||
mov rax, 60
|
call _rt_thread_finish
|
||||||
syscall
|
|
||||||
; Just to be sure...
|
; Just to be sure...
|
||||||
hlt
|
hlt
|
||||||
.exit:
|
.exit:
|
||||||
|
|
1
cia.c
1
cia.c
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
// Base includes
|
// Base includes
|
||||||
#include <cia/def.h>
|
#include <cia/def.h>
|
||||||
#include <cia/internal.h>
|
|
||||||
|
|
||||||
// Platform-dependent sources
|
// Platform-dependent sources
|
||||||
#include _CIA_OS_CONF
|
#include _CIA_OS_CONF
|
||||||
|
|
|
@ -11,13 +11,28 @@ struct Cia_CRT_Params {
|
||||||
void *tls_image_base;
|
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 typedef Cia_TCB;
|
||||||
struct Cia_TCB {
|
struct Cia_TCB {
|
||||||
u64 thread_id;
|
/* +0x00 */ u64 thread_id;
|
||||||
u64 parent_id;
|
/* +0x08 */ u64 parent_id;
|
||||||
u64 pad0[3];
|
/* +0x10 */ u32 thread_behaviour; /* One of the CIA_THREAD_BEHAVIOR_* constants */
|
||||||
u64 stack_canary;
|
/* +0x14 */ u32 thread_finished;
|
||||||
u64 pad1[2];
|
/* +0x18 */ u32 pad0;
|
||||||
|
/* +0x1c */ i32 exit_code;
|
||||||
|
/* +0x20 */ u64 pad1;
|
||||||
|
/* +0x28 */ u64 stack_canary;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,3 +17,5 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
|
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);
|
|
@ -55,7 +55,7 @@ struct _RT_Thread {
|
||||||
};
|
};
|
||||||
static _RT_Status _rt_thread_current(_RT_Thread *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_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_detach(_RT_Thread *thread);
|
||||||
static _RT_Status _rt_thread_terminate(_RT_Thread *thread);
|
static _RT_Status _rt_thread_terminate(_RT_Thread *thread);
|
||||||
static _RT_Status _rt_thread_sleep(u64 time);
|
static _RT_Status _rt_thread_sleep(u64 time);
|
||||||
|
|
|
@ -5,6 +5,8 @@ static u64 cia_stack_size;
|
||||||
static u64 cia_tls_image_size;
|
static u64 cia_tls_image_size;
|
||||||
static void *cia_tls_image_base;
|
static void *cia_tls_image_base;
|
||||||
|
|
||||||
|
#include <cia/internal.h>
|
||||||
|
|
||||||
#include <linux/futex.h>
|
#include <linux/futex.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
extern i64 _cia_start_thread(
|
extern i64 _rt_thread_start(
|
||||||
u64 flags,
|
u64 flags,
|
||||||
void *stack_base,
|
void *stack_base,
|
||||||
int *parent_tid,
|
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
|
// Initialize the _RT_Thread handle, which would point to
|
||||||
// the TCB
|
// the TCB
|
||||||
thread->handle = tcb;
|
thread->handle = tcb;
|
||||||
|
tcb->thread_finished = 0;
|
||||||
// Create the new thread
|
// Create the new thread
|
||||||
u64 flags = 0;
|
u64 flags = 0;
|
||||||
// flags |= CLONE_CHILD_CLEARTID;
|
// 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;
|
int *parent_tid = (int *)&tcb->parent_id;
|
||||||
*child_tid = 1;
|
*child_tid = 1;
|
||||||
*parent_tid = 0;
|
*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) {
|
if(ret < 0) {
|
||||||
return _RT_ERROR_GENERIC;
|
return _RT_ERROR_GENERIC;
|
||||||
}
|
}
|
||||||
return _RT_STATUS_OK;
|
return _RT_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static _RT_Status _rt_thread_join(_RT_Thread *thread) {
|
void _rt_thread_finish(int exit_code) {
|
||||||
return _RT_ERROR_NOT_IMPLEMENTED;
|
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) {
|
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) {
|
static _RT_Status _rt_thread_terminate(_RT_Thread *thread) {
|
||||||
|
|
|
@ -5,4 +5,20 @@ int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) {
|
||||||
return thrd_success;
|
return thrd_success;
|
||||||
}
|
}
|
||||||
return thrd_error;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ static void print_int(i64 number) {
|
||||||
|
|
||||||
static Cia_Mutex g_print_mutex;
|
static Cia_Mutex g_print_mutex;
|
||||||
static Cia_Mutex g_mutex;
|
static Cia_Mutex g_mutex;
|
||||||
static volatile _Atomic i64 n_completed = 0;
|
|
||||||
static volatile i64 counter = 0;
|
static volatile i64 counter = 0;
|
||||||
|
|
||||||
int thrd_func(void *arg) {
|
int thrd_func(void *arg) {
|
||||||
|
@ -46,12 +45,6 @@ int thrd_func(void *arg) {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
cia_mutex_unlock(&g_mutex);
|
cia_mutex_unlock(&g_mutex);
|
||||||
}
|
}
|
||||||
atomic_fetch_add(&n_completed, 1);
|
|
||||||
for(;;) {
|
|
||||||
if(n_completed == 2) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cia_mutex_lock(&g_print_mutex);
|
cia_mutex_lock(&g_print_mutex);
|
||||||
print_string("child thread: counter = ");
|
print_string("child thread: counter = ");
|
||||||
print_int(counter);
|
print_int(counter);
|
||||||
|
@ -76,12 +69,8 @@ int main() {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
cia_mutex_unlock(&g_mutex);
|
cia_mutex_unlock(&g_mutex);
|
||||||
}
|
}
|
||||||
atomic_fetch_add(&n_completed, 1);
|
int exit_code;
|
||||||
for(;;) {
|
thrd_join(thrd, &exit_code);
|
||||||
if(n_completed == 2) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cia_mutex_lock(&g_print_mutex);
|
cia_mutex_lock(&g_print_mutex);
|
||||||
print_string("main thread: counter = ");
|
print_string("main thread: counter = ");
|
||||||
print_int(counter);
|
print_int(counter);
|
||||||
|
|
Loading…
Reference in New Issue