-
-
Notifications
You must be signed in to change notification settings - Fork 654
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Thread creation * Proper thread creation and exit * Join/Detach protocol * Added semaphore with futex (hopefully fast)
- Loading branch information
Showing
30 changed files
with
792 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#if 0 | ||
/*─────────────────────────────────────────────────────────────────╗ | ||
│ To the extent possible under law, Justine Tunney has waived │ | ||
│ all copyright and related or neighboring rights to this file, │ | ||
│ as it is written in the following disclaimers: │ | ||
│ • http://unlicense.org/ │ | ||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │ | ||
╚─────────────────────────────────────────────────────────────────*/ | ||
#endif | ||
#include "libc/stdio/stdio.h" | ||
#include "libc/thread/create.h" | ||
#include "libc/thread/self.h" | ||
#include "libc/thread/detach.h" | ||
#include "libc/thread/join.h" | ||
#include "libc/thread/nativesem.h" | ||
#include "libc/time/time.h" | ||
|
||
cthread_native_sem_t semaphore; | ||
|
||
int worker(void* arg) { | ||
cthread_native_sem_signal(&semaphore); | ||
|
||
cthread_t self = cthread_self(); | ||
int tid = self->tid; | ||
sleep(1); | ||
//sleep(10000); | ||
//printf("[%p] %d\n", self, tid); | ||
(void)arg; | ||
return 4; | ||
} | ||
|
||
int main() { | ||
cthread_native_sem_init(&semaphore, 0); | ||
|
||
cthread_t thread; | ||
int rc = cthread_create(&thread, NULL, &worker, NULL); | ||
if (rc == 0) { | ||
cthread_native_sem_wait(&semaphore, 0, 0, NULL); | ||
//printf("thread created: %p\n", thread); | ||
sleep(1); | ||
#if 1 | ||
cthread_join(thread, &rc); | ||
#else | ||
rc = cthread_detach(thread); | ||
sleep(2); | ||
#endif | ||
cthread_native_sem_signal(&semaphore); | ||
cthread_native_sem_wait(&semaphore, 0, 0, NULL); | ||
//printf("thread joined: %p -> %d\n", thread, rc); | ||
} else { | ||
printf("ERROR: thread could not be started: %d\n", rc); | ||
} | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#ifndef COSMOPOLITAN_LIBC_LINUX_CLONE_H_ | ||
#define COSMOPOLITAN_LIBC_LINUX_CLONE_H_ | ||
#if !(__ASSEMBLER__ + __LINKER__ + 0) | ||
|
||
forceinline long LinuxClone(unsigned long flags, void* stack, int* parent_tid, int* child_tid, void* tls) { | ||
long rc; | ||
register int* child_tid_ asm("r10") = child_tid; | ||
register void* tls_ asm("r8") = tls; | ||
asm volatile("syscall" | ||
: "=a"(rc) | ||
: "0"(56), "D"(flags), "S"(stack), "d"(parent_tid), "r"(child_tid_), "r"(tls_) | ||
: "rcx", "r11", "memory"); | ||
return rc; | ||
} | ||
|
||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ | ||
#endif /* COSMOPOLITAN_LIBC_LINUX_MMAP_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
#include "libc/sysv/consts/syscon.internal.h" | ||
.syscon misc,FUTEX_PRIVATE_FLAG,0,0,0,0x80,0x80,0 | ||
.syscon misc,FUTEX_PRIVATE_FLAG,128,0,0,0x80,0x80,0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
#include "libc/sysv/consts/syscon.internal.h" | ||
.syscon misc,FUTEX_REQUEUE,0,0,0,3,3,0 | ||
.syscon misc,FUTEX_REQUEUE,3,0,0,3,3,0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
#include "libc/sysv/consts/syscon.internal.h" | ||
.syscon misc,FUTEX_REQUEUE_PRIVATE,0,0,0,131,131,0 | ||
.syscon misc,FUTEX_REQUEUE_PRIVATE,131,0,0,131,131,0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
#include "libc/sysv/consts/syscon.internal.h" | ||
.syscon misc,FUTEX_WAIT_PRIVATE,0,0,0,129,129,0 | ||
.syscon misc,FUTEX_WAIT_PRIVATE,128,0,0,129,129,0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
#include "libc/sysv/consts/syscon.internal.h" | ||
.syscon misc,FUTEX_WAKE,0,0,0,2,2,0 | ||
.syscon misc,FUTEX_WAKE,1,0,0,2,2,0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
#include "libc/sysv/consts/syscon.internal.h" | ||
.syscon misc,FUTEX_WAKE_PRIVATE,0,0,0,130,130,0 | ||
.syscon misc,FUTEX_WAKE_PRIVATE,129,0,0,130,130,0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ | ||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ | ||
╞══════════════════════════════════════════════════════════════════════════════╡ | ||
│ Copyright 2020 Justine Alexandra Roberts Tunney │ | ||
│ │ | ||
│ Permission to use, copy, modify, and/or distribute this software for │ | ||
│ any purpose with or without fee is hereby granted, provided that the │ | ||
│ above copyright notice and this permission notice appear in all copies. │ | ||
│ │ | ||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ | ||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ | ||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ | ||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ | ||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ | ||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ | ||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ | ||
│ PERFORMANCE OF THIS SOFTWARE. │ | ||
╚─────────────────────────────────────────────────────────────────────────────*/ | ||
#include "libc/thread/attr.h" | ||
#include "libc/errno.h" | ||
|
||
#define MIN_STACKSIZE (8*PAGESIZE) | ||
#define MIN_GUARDSIZE PAGESIZE | ||
|
||
// CTOR/DTOR | ||
int cthread_attr_init(cthread_attr_t* attr) { | ||
attr->stacksize = 1024*PAGESIZE; // 4 MiB | ||
attr->guardsize = 16*PAGESIZE; // 64 KiB | ||
attr->mode = CTHREAD_CREATE_JOINABLE; | ||
return 0; | ||
} | ||
int cthread_attr_destroy(cthread_attr_t* attr) { | ||
(void)attr; | ||
return 0; | ||
} | ||
|
||
// stacksize | ||
int cthread_attr_setstacksize(cthread_attr_t* attr, size_t size) { | ||
if (size & (PAGESIZE-1)) return EINVAL; | ||
if (size < MIN_STACKSIZE) return EINVAL; | ||
attr->stacksize = size; | ||
return 0; | ||
} | ||
size_t cthread_attr_getstacksize(const cthread_attr_t* attr) { | ||
return attr->stacksize; | ||
} | ||
|
||
// guardsize | ||
int cthread_attr_setguardsize(cthread_attr_t* attr, size_t size) { | ||
if (size & (PAGESIZE-1)) return EINVAL; | ||
if (size < MIN_GUARDSIZE) return EINVAL; | ||
attr->guardsize = size; | ||
return 0; | ||
} | ||
size_t cthread_attr_getguardsize(const cthread_attr_t* attr) { | ||
return attr->guardsize; | ||
} | ||
|
||
// detachstate | ||
int cthread_attr_setdetachstate(cthread_attr_t* attr, int mode) { | ||
if (mode & ~(CTHREAD_CREATE_JOINABLE | CTHREAD_CREATE_DETACHED)) return EINVAL; | ||
attr->mode = mode; | ||
return 0; | ||
} | ||
int cthread_attr_getdetachstate(const cthread_attr_t* attr) { | ||
return attr->mode; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#ifndef COSMOPOLITAN_LIBC_THREAD_ATTR_H_ | ||
#define COSMOPOLITAN_LIBC_THREAD_ATTR_H_ | ||
#if !(__ASSEMBLER__ + __LINKER__ + 0) | ||
COSMOPOLITAN_C_START_ | ||
|
||
/** | ||
* @fileoverview cosmopolitan thread attributes | ||
*/ | ||
|
||
#define CTHREAD_CREATE_DETACHED 1 | ||
#define CTHREAD_CREATE_JOINABLE 0 | ||
|
||
typedef struct cthread_attr_t { | ||
size_t stacksize, guardsize; | ||
int mode; | ||
} cthread_attr_t; | ||
|
||
// CTOR/DTOR | ||
int cthread_attr_init(cthread_attr_t*); | ||
int cthread_attr_destroy(cthread_attr_t*); | ||
|
||
// stacksize | ||
int cthread_attr_setstacksize(cthread_attr_t*, size_t); | ||
size_t thread_attr_getstacksize(const cthread_attr_t*); | ||
|
||
// guardsize | ||
int cthread_attr_setguardsize(cthread_attr_t*, size_t); | ||
size_t cthread_attr_getguardsize(const cthread_attr_t*); | ||
|
||
// detachstate | ||
int cthread_attr_setdetachstate(cthread_attr_t*, int); | ||
int cthread_attr_getdetachstate(const cthread_attr_t*); | ||
|
||
COSMOPOLITAN_C_END_ | ||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ | ||
#endif /* COSMOPOLITAN_LIBC_THREAD_ATTR_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ | ||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ | ||
╞══════════════════════════════════════════════════════════════════════════════╡ | ||
│ Copyright 2020 Justine Alexandra Roberts Tunney │ | ||
│ │ | ||
│ Permission to use, copy, modify, and/or distribute this software for │ | ||
│ any purpose with or without fee is hereby granted, provided that the │ | ||
│ above copyright notice and this permission notice appear in all copies. │ | ||
│ │ | ||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ | ||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ | ||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ | ||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ | ||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ | ||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ | ||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ | ||
│ PERFORMANCE OF THIS SOFTWARE. │ | ||
╚─────────────────────────────────────────────────────────────────────────────*/ | ||
#include "libc/thread/create.h" | ||
#include "libc/linux/clone.h" | ||
#include "libc/runtime/runtime.h" | ||
#include "libc/sysv/consts/nr.h" | ||
#include "libc/sysv/consts/clone.h" | ||
#include "libc/sysv/consts/map.h" | ||
#include "libc/sysv/consts/prot.h" | ||
#include "libc/errno.h" | ||
|
||
|
||
static cthread_t _thread_allocate(const cthread_attr_t* attr) { | ||
size_t stacksize = attr->stacksize; | ||
size_t guardsize = attr->guardsize; | ||
// FIXME: properly count TLS size | ||
size_t tlssize = 0; | ||
|
||
size_t totalsize = 3*guardsize + stacksize + tlssize + sizeof(struct cthread_descriptor_t); | ||
totalsize = (totalsize + PAGESIZE-1) & -PAGESIZE; | ||
|
||
uintptr_t mem = (uintptr_t)mmap(NULL, totalsize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); | ||
if (mem == -1) return NULL; | ||
|
||
void* alloc_bottom = (void*) mem; | ||
void* stack_bottom = (void*)(mem + guardsize); | ||
void* stack_top = (void*)(mem + guardsize + stacksize); | ||
void* tls_bottom = (void*)(mem + guardsize + stacksize + guardsize); | ||
void* tls_top = (void*)(mem + totalsize - guardsize); | ||
void* alloc_top = (void*)(mem + totalsize); | ||
|
||
if (mprotect(stack_bottom, (uintptr_t)stack_top - (uintptr_t)stack_bottom, PROT_READ | PROT_WRITE) != 0 || | ||
mprotect(tls_bottom, (uintptr_t)tls_top - (uintptr_t)tls_bottom, PROT_READ | PROT_WRITE) != 0) { | ||
munmap(alloc_bottom, totalsize); | ||
return NULL; | ||
} | ||
|
||
cthread_t td = (cthread_t)tls_top - 1; | ||
td->self = td; | ||
td->stack.top = stack_top; | ||
td->stack.bottom = stack_bottom; | ||
td->tls.top = tls_top; | ||
td->tls.bottom = tls_bottom; | ||
td->alloc.top = alloc_top; | ||
td->alloc.bottom = alloc_bottom; | ||
td->state = (attr->mode & CTHREAD_CREATE_DETACHED) ? cthread_detached : cthread_started; | ||
|
||
return td; | ||
} | ||
|
||
int cthread_create(cthread_t*restrict p, const cthread_attr_t*restrict attr, int (*func)(void*), void*restrict arg) { | ||
extern wontreturn void _thread_run(int(*func)(void*), void* arg); | ||
|
||
cthread_attr_t default_attr; | ||
cthread_attr_init(&default_attr); | ||
cthread_t td = _thread_allocate(attr ? attr : &default_attr); | ||
cthread_attr_destroy(&default_attr); | ||
if (!td) return errno; | ||
|
||
*p = td; | ||
|
||
register cthread_t td_ asm("r8") = td; | ||
register int* ptid_ asm("rdx") = &td->tid; | ||
register int* ctid_ asm("r10") = &td->tid; | ||
register int(*func_)(void*) asm("r12") = func; | ||
register void* arg_ asm("r13") = arg; | ||
|
||
long flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_PARENT | CLONE_THREAD | /*CLONE_IO |*/ CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; | ||
int rc; | ||
// asm ensures the (empty) stack of the child thread is not used | ||
asm volatile( | ||
"syscall\n\t" // clone | ||
"test\t%0, %0\n\t" // if not child | ||
"jne\t.L.cthread_create.%=\n\t" // jump to `parent` label | ||
"xor\t%%rbp, %%rbp\n\t" // reset stack frame pointer | ||
"mov\t%2, %%rdi\n\t" | ||
"call\t*%1\n\t" // call `func(arg)` | ||
"mov\t%%rax, %%rdi\n\t" | ||
"jmp\tcthread_exit\n" // exit thread | ||
".L.cthread_create.%=:" | ||
: "=a"(rc) | ||
: "r"(func_), "r"(arg_), "0"(__NR_clone), "D"(flags), "S"(td->stack.top), "r"(ptid_), "r"(ctid_), "r"(td_) | ||
: "rcx", "r11", "cc", "memory" | ||
); | ||
if (__builtin_expect(rc < 0, 0)) { | ||
// `clone` has failed. The thread must be deallocated. | ||
size_t size = (intptr_t)(td->alloc.top) - (intptr_t)(td->alloc.bottom); | ||
munmap(td->alloc.bottom, size); | ||
return -rc; | ||
} | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#ifndef COSMOPOLITAN_LIBC_THREAD_CREATE_H_ | ||
#define COSMOPOLITAN_LIBC_THREAD_CREATE_H_ | ||
#include "libc/thread/attr.h" | ||
#include "libc/thread/descriptor.h" | ||
#if !(__ASSEMBLER__ + __LINKER__ + 0) | ||
COSMOPOLITAN_C_START_ | ||
|
||
/** | ||
* @fileoverview Create a cosmopolitan thread | ||
*/ | ||
|
||
int cthread_create(cthread_t*restrict, const cthread_attr_t*restrict, int (*)(void*), void*restrict); | ||
|
||
|
||
COSMOPOLITAN_C_END_ | ||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ | ||
#endif /* COSMOPOLITAN_LIBC_THREAD_CREATE_H_ */ |
Oops, something went wrong.