mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
[WIP] Threading (#282)
* Thread creation * Proper thread creation and exit * Join/Detach protocol * Added semaphore with futex (hopefully fast)
This commit is contained in:
parent
d852640a1e
commit
a0b39f886c
30 changed files with 792 additions and 12 deletions
3
Makefile
3
Makefile
|
@ -114,6 +114,7 @@ include third_party/gdtoa/gdtoa.mk # │ You can finally call malloc()
|
|||
include libc/time/time.mk # │
|
||||
include libc/alg/alg.mk # │
|
||||
include libc/stdio/stdio.mk # │
|
||||
include libc/thread/thread.mk # │
|
||||
include net/net.mk # │
|
||||
include libc/log/log.mk # │
|
||||
include third_party/bzip2/bzip2.mk # │
|
||||
|
@ -284,6 +285,7 @@ COSMOPOLITAN_OBJECTS = \
|
|||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_FMT \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
LIBC_THREAD \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
|
@ -311,6 +313,7 @@ COSMOPOLITAN_HEADERS = \
|
|||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_UNICODE \
|
||||
|
|
|
@ -61,6 +61,7 @@ EXAMPLES_DIRECTDEPS = \
|
|||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_UNICODE \
|
||||
|
|
54
examples/thread.c
Normal file
54
examples/thread.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -31,6 +31,7 @@ o/$(MODE)/libc: o/$(MODE)/libc/alg \
|
|||
o/$(MODE)/libc/stubs \
|
||||
o/$(MODE)/libc/sysv \
|
||||
o/$(MODE)/libc/testlib \
|
||||
o/$(MODE)/libc/thread \
|
||||
o/$(MODE)/libc/time \
|
||||
o/$(MODE)/libc/tinymath \
|
||||
o/$(MODE)/libc/unicode \
|
||||
|
|
17
libc/linux/clone.h
Normal file
17
libc/linux/clone.h
Normal file
|
@ -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_ */
|
|
@ -1928,13 +1928,13 @@ syscon misc DAY_5 0x02000b 11 11 10 10 0
|
|||
syscon misc DAY_6 0x02000c 12 12 11 11 0
|
||||
syscon misc DAY_7 0x02000d 13 13 12 12 0
|
||||
|
||||
syscon misc FUTEX_PRIVATE_FLAG 0 0 0 0x80 0x80 0
|
||||
syscon misc FUTEX_REQUEUE 0 0 0 3 3 0
|
||||
syscon misc FUTEX_REQUEUE_PRIVATE 0 0 0 131 131 0
|
||||
syscon misc FUTEX_PRIVATE_FLAG 128 0 0 0x80 0x80 0
|
||||
syscon misc FUTEX_REQUEUE 3 0 0 3 3 0
|
||||
syscon misc FUTEX_REQUEUE_PRIVATE 131 0 0 131 131 0
|
||||
syscon misc FUTEX_WAIT 0 0 0 1 1 0
|
||||
syscon misc FUTEX_WAIT_PRIVATE 0 0 0 129 129 0
|
||||
syscon misc FUTEX_WAKE 0 0 0 2 2 0
|
||||
syscon misc FUTEX_WAKE_PRIVATE 0 0 0 130 130 0
|
||||
syscon misc FUTEX_WAIT_PRIVATE 128 0 0 129 129 0
|
||||
syscon misc FUTEX_WAKE 1 0 0 2 2 0
|
||||
syscon misc FUTEX_WAKE_PRIVATE 129 0 0 130 130 0
|
||||
|
||||
syscon misc HOST_NOT_FOUND 1 1 1 1 1 0x2af9 # unix consensus
|
||||
syscon misc HOST_NAME_MAX 0x40 0 0 255 255 0
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
67
libc/thread/attr.c
Normal file
67
libc/thread/attr.c
Normal file
|
@ -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;
|
||||
}
|
36
libc/thread/attr.h
Normal file
36
libc/thread/attr.h
Normal file
|
@ -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_ */
|
108
libc/thread/create.c
Normal file
108
libc/thread/create.c
Normal file
|
@ -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;
|
||||
}
|
17
libc/thread/create.h
Normal file
17
libc/thread/create.h
Normal file
|
@ -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_ */
|
33
libc/thread/descriptor.h
Normal file
33
libc/thread/descriptor.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview thread types
|
||||
*/
|
||||
|
||||
enum cthread_state {
|
||||
cthread_started = 0,
|
||||
cthread_joining = 1,
|
||||
cthread_finished = 2,
|
||||
cthread_detached = 4,
|
||||
};
|
||||
|
||||
|
||||
struct cthread_descriptor_t {
|
||||
struct cthread_descriptor_t* self; // mandatory for TLS
|
||||
struct {
|
||||
void *top, *bottom;
|
||||
} stack, tls, alloc;
|
||||
int state;
|
||||
int tid;
|
||||
int rc;
|
||||
void* pthread_ret_ptr;
|
||||
};
|
||||
|
||||
typedef struct cthread_descriptor_t* cthread_t;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_ */
|
31
libc/thread/detach.c
Normal file
31
libc/thread/detach.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*-*- 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/detach.h"
|
||||
#include "libc/thread/descriptor.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
int cthread_detach(cthread_t td) {
|
||||
int state;
|
||||
asm volatile("lock xadd\t%1, %0" : "+m"(td->state), "=r"(state) : "1"(cthread_detached) : "cc");
|
||||
if ((state & cthread_finished)) {
|
||||
size_t size = (intptr_t)(td->alloc.top) - (intptr_t)(td->alloc.bottom);
|
||||
munmap(td->alloc.bottom, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
16
libc/thread/detach.h
Normal file
16
libc/thread/detach.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_DETACH_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_DETACH_H_
|
||||
#include "libc/thread/descriptor.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview detach a thread
|
||||
*/
|
||||
|
||||
int cthread_detach(cthread_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_DETACH_H_ */
|
||||
|
44
libc/thread/exit.c
Normal file
44
libc/thread/exit.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*-*- 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/exit.h"
|
||||
#include "libc/thread/self.h"
|
||||
#include "libc/thread/descriptor.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
||||
wontreturn void cthread_exit(int rc) {
|
||||
cthread_t td = cthread_self();
|
||||
td->rc = rc;
|
||||
size_t size = (intptr_t)(td->alloc.top) - (intptr_t)(td->alloc.bottom);
|
||||
|
||||
int state;
|
||||
asm volatile(
|
||||
"lock xadd\t%1, %0\n\t" // mark thread as finished
|
||||
"test\t%2, %b1\n\t" // test if thread was detached
|
||||
"jz .L.cthread_exit.%=\n\t" // skip unmap if not detached
|
||||
"syscall\n" // unmap thread
|
||||
".L.cthread_exit.%=:\n\t"
|
||||
"mov\t%%rbx, %%rdi\n\t" //rc
|
||||
"mov\t$60, %%rax\n\t"
|
||||
"syscall" // thread exit
|
||||
: "+m"(td->state), "=&r"(state)
|
||||
: "I"(cthread_detached), "1"(cthread_finished), "a"(__NR_munmap), "b"(rc), "D"(td->alloc.bottom), "S"(size)
|
||||
: "rcx", "r11", "cc", "memory"
|
||||
);
|
||||
unreachable;
|
||||
}
|
14
libc/thread/exit.h
Normal file
14
libc/thread/exit.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_EXIT_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_EXIT_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview exit the current thread
|
||||
*/
|
||||
|
||||
wontreturn void cthread_exit(int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_EXIT_H_ */
|
49
libc/thread/join.c
Normal file
49
libc/thread/join.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*-*- 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/join.h"
|
||||
#include "libc/thread/descriptor.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/futex.h"
|
||||
|
||||
int cthread_join(cthread_t td, int* rc) {
|
||||
int tid = td->tid; // tid must be loaded before lock xadd
|
||||
// otherwise, tid could be set to 0 even though `state` is not finished
|
||||
|
||||
// mark thread as joining
|
||||
int state;
|
||||
asm volatile("lock xadd\t%1, %0" : "+m"(td->state), "=r"(state) : "1"(cthread_joining) : "cc");
|
||||
|
||||
if (!(state & cthread_finished)) {
|
||||
int flags = FUTEX_WAIT; // PRIVATE makes it hang
|
||||
register struct timespec* timeout asm("r10") = NULL;
|
||||
asm volatile (
|
||||
"syscall"
|
||||
:
|
||||
: "a"(__NR_futex), "D"(&td->tid), "S"(flags), "d"(tid), "r"(timeout)
|
||||
: "rcx", "r11", "cc", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
*rc = td->rc;
|
||||
|
||||
size_t size = (intptr_t)(td->alloc.top) - (intptr_t)(td->alloc.bottom);
|
||||
munmap(td->alloc.bottom, size);
|
||||
return 0;
|
||||
}
|
15
libc/thread/join.h
Normal file
15
libc/thread/join.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_JOIN_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_JOIN_H_
|
||||
#include "libc/thread/descriptor.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview join a thread
|
||||
*/
|
||||
|
||||
int cthread_join(cthread_t, int*);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_JOIN_H_ */
|
112
libc/thread/nativesem.c
Normal file
112
libc/thread/nativesem.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*-*- 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/nativesem.h"
|
||||
#include "libc/thread/yield.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/futex.h"
|
||||
#include "libc/bits/atomic.h"
|
||||
|
||||
#define CTHREAD_THREAD_VAL_BITS 32
|
||||
|
||||
int cthread_native_sem_init(cthread_native_sem_t* sem, int count) {
|
||||
sem->linux.count = count;
|
||||
return 0;
|
||||
}
|
||||
int cthread_native_sem_destroy(cthread_native_sem_t* sem) {
|
||||
(void)sem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cthread_native_sem_signal(cthread_native_sem_t* sem) {
|
||||
uint64_t count;
|
||||
asm volatile("lock xadd\t%1, %0" : "+m"(sem->linux.count), "=r"(count) : "1"(1) : "cc");
|
||||
|
||||
if ((count >> CTHREAD_THREAD_VAL_BITS)) {
|
||||
int flags = FUTEX_WAKE;
|
||||
|
||||
// WARNING: an offset of 4 bytes would be required on little-endian archs
|
||||
void* wait_address = &sem->linux.count;
|
||||
asm volatile (
|
||||
"syscall"
|
||||
:
|
||||
: "a"(__NR_futex), "D"(wait_address), "S"(flags), "d"(1)
|
||||
: "rcx", "r11", "cc", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cthread_native_sem_wait_slow(cthread_native_sem_t* sem, const struct timespec* timeout) {
|
||||
uint64_t count;
|
||||
|
||||
// record current thread as waiter
|
||||
asm volatile("lock xadd\t%1, %0" : "+m"(sem->linux.count), "=r"(count) : "1"((uint64_t)1 << CTHREAD_THREAD_VAL_BITS) : "cc");
|
||||
|
||||
for (;;) {
|
||||
// try to acquire the semaphore, as well as remove itself from waiters
|
||||
if ((uint32_t)count > 0 && atomic_compare_exchange_weak(&sem->linux.count, count, count - 1 - ((uint64_t)1 << CTHREAD_THREAD_VAL_BITS))) break;
|
||||
|
||||
int flags = FUTEX_WAIT;
|
||||
register struct timespec* timeout_ asm("r10") = timeout;
|
||||
|
||||
// WARNING: an offset of 4 bytes would be required on little-endian archs
|
||||
void* wait_address = &sem->linux.count;
|
||||
asm volatile (
|
||||
"syscall"
|
||||
:
|
||||
: "a"(__NR_futex), "D"(wait_address), "S"(flags), "d"(count), "r"(timeout_)
|
||||
: "rcx", "r11", "cc", "memory"
|
||||
);
|
||||
count = atomic_load(&sem->linux.count);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cthread_native_sem_wait_spin_yield(cthread_native_sem_t* sem, uint64_t count, int yield, const struct timespec* timeout) {
|
||||
// spin on yield
|
||||
while (yield-- > 0) {
|
||||
if ((count >> CTHREAD_THREAD_VAL_BITS) != 0) break; // a thread is already waiting in queue
|
||||
if ((uint32_t)count > 0 && atomic_compare_exchange_weak(&sem->linux.count, count, count-1)) return 0;
|
||||
cthread_yield();
|
||||
}
|
||||
|
||||
return cthread_native_sem_wait_slow(sem, timeout);
|
||||
}
|
||||
|
||||
int cthread_native_sem_wait_spin(cthread_native_sem_t* sem, uint64_t count, int spin, int yield, const struct timespec* timeout) {
|
||||
// spin on pause
|
||||
while (spin-- > 0) {
|
||||
if ((count >> CTHREAD_THREAD_VAL_BITS) != 0) break;
|
||||
if ((uint32_t)count > 0 && atomic_compare_exchange_weak(&sem->linux.count, count, count-1)) return 0;
|
||||
asm volatile ("pause");
|
||||
}
|
||||
|
||||
return cthread_native_sem_wait_spin_yield(sem, count, yield, timeout);
|
||||
}
|
||||
|
||||
int cthread_native_sem_wait(cthread_native_sem_t* sem, int spin, int yield, const struct timespec* timeout) {
|
||||
uint64_t count = atomic_load(&sem->linux.count);
|
||||
|
||||
// uncontended
|
||||
if ((count >> 32) == 0 && (uint32_t)count > 0 && atomic_compare_exchange_weak(&sem->linux.count, count, count-1)) return 0;
|
||||
|
||||
return cthread_native_sem_wait_spin(sem, count, spin, yield, timeout);
|
||||
}
|
28
libc/thread/nativesem.h
Normal file
28
libc/thread/nativesem.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_NATIVESEM_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_NATIVESEM_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview native semaphore for implementation details
|
||||
*/
|
||||
|
||||
typedef union cthread_native_sem_t {
|
||||
struct {
|
||||
uint64_t count;
|
||||
} linux;
|
||||
} cthread_native_sem_t;
|
||||
|
||||
struct timespec;
|
||||
|
||||
int cthread_native_sem_init(cthread_native_sem_t*, int);
|
||||
int cthread_native_sem_destroy(cthread_native_sem_t*);
|
||||
|
||||
int cthread_native_sem_wait(cthread_native_sem_t*, int, int, const struct timespec*);
|
||||
int cthread_native_sem_signal(cthread_native_sem_t*);
|
||||
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_SELF_H_ */
|
||||
|
21
libc/thread/self.c
Normal file
21
libc/thread/self.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*-*- 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/self.h"
|
||||
|
||||
extern inline cthread_t cthread_self(void);
|
20
libc/thread/self.h
Normal file
20
libc/thread/self.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_SELF_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_SELF_H_
|
||||
#include "libc/thread/descriptor.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview get the thread descriptor of the current thread
|
||||
*/
|
||||
|
||||
inline cthread_t cthread_self(void) {
|
||||
cthread_t self;
|
||||
asm ("mov %%fs:0, %0" : "=r"(self));
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_SELF_H_ */
|
55
libc/thread/thread.mk
Normal file
55
libc/thread/thread.mk
Normal file
|
@ -0,0 +1,55 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += LIBC_THREAD
|
||||
|
||||
LIBC_THREAD_ARTIFACTS += LIBC_THREAD_A
|
||||
LIBC_THREAD = $(LIBC_THREAD_A_DEPS) $(LIBC_THREAD_A)
|
||||
LIBC_THREAD_A = o/$(MODE)/libc/thread/thread.a
|
||||
LIBC_THREAD_A_FILES := $(wildcard libc/thread/*)
|
||||
LIBC_THREAD_A_HDRS = $(filter %.h,$(LIBC_THREAD_A_FILES))
|
||||
LIBC_THREAD_A_SRCS_S = $(filter %.S,$(LIBC_THREAD_A_FILES))
|
||||
LIBC_THREAD_A_SRCS_C = $(filter %.c,$(LIBC_THREAD_A_FILES))
|
||||
|
||||
LIBC_THREAD_A_SRCS = \
|
||||
$(LIBC_THREAD_A_SRCS_S) \
|
||||
$(LIBC_THREAD_A_SRCS_C)
|
||||
|
||||
LIBC_THREAD_A_OBJS = \
|
||||
$(LIBC_THREAD_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(LIBC_THREAD_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
LIBC_THREAD_A_CHECKS = \
|
||||
$(LIBC_THREAD_A).pkg \
|
||||
$(LIBC_THREAD_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
LIBC_THREAD_A_DIRECTDEPS = \
|
||||
LIBC_STUBS \
|
||||
LIBC_CALLS \
|
||||
LIBC_INTRIN \
|
||||
LIBC_BITS \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_NEXGEN32E
|
||||
|
||||
LIBC_THREAD_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_THREAD_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(LIBC_THREAD_A): libc/thread/ \
|
||||
$(LIBC_THREAD_A).pkg \
|
||||
$(LIBC_THREAD_A_OBJS)
|
||||
|
||||
$(LIBC_THREAD_A).pkg: \
|
||||
$(LIBC_THREAD_A_OBJS) \
|
||||
$(foreach x,$(LIBC_THREAD_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
LIBC_THREAD_LIBS = $(foreach x,$(LIBC_THREAD_ARTIFACTS),$($(x)))
|
||||
LIBC_THREAD_SRCS = $(foreach x,$(LIBC_THREAD_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_THREAD_HDRS = $(foreach x,$(LIBC_THREAD_ARTIFACTS),$($(x)_HDRS))
|
||||
LIBC_THREAD_CHECKS = $(foreach x,$(LIBC_THREAD_ARTIFACTS),$($(x)_CHECKS))
|
||||
LIBC_THREAD_OBJS = $(foreach x,$(LIBC_THREAD_ARTIFACTS),$($(x)_OBJS))
|
||||
$(LIBC_THREAD_OBJS): $(BUILD_FILES) libc/thread/thread.mk
|
||||
|
||||
.PHONY: o/$(MODE)/libc/thread
|
||||
o/$(MODE)/libc/thread: $(LIBC_THREAD_CHECKS)
|
24
libc/thread/yield.c
Normal file
24
libc/thread/yield.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*-*- 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/yield.h"
|
||||
#include "libc/calls/calls.h"
|
||||
|
||||
int cthread_yield(void) {
|
||||
return sched_yield();
|
||||
}
|
14
libc/thread/yield.h
Normal file
14
libc/thread/yield.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_YIELD_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_YIELD_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview yield thread to OS scheduler
|
||||
*/
|
||||
|
||||
int cthread_yield(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_YIELD_H_ */
|
Loading…
Reference in a new issue