mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-07 02:10:27 +00:00
Join/Detach protocol
This commit is contained in:
parent
fb2dd3ff89
commit
cf598d09e4
12 changed files with 242 additions and 66 deletions
|
@ -9,19 +9,34 @@
|
||||||
#endif
|
#endif
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/thread/create.h"
|
#include "libc/thread/create.h"
|
||||||
|
#include "libc/thread/self.h"
|
||||||
|
#include "libc/thread/detach.h"
|
||||||
|
#include "libc/thread/join.h"
|
||||||
#include "libc/time/time.h"
|
#include "libc/time/time.h"
|
||||||
|
|
||||||
int worker(void* arg) {
|
int worker(void* arg) {
|
||||||
|
cthread_t self = cthread_self();
|
||||||
|
int tid = self->tid;
|
||||||
|
sleep(1);
|
||||||
|
//sleep(10000);
|
||||||
|
//printf("[%p] %d\n", self, tid);
|
||||||
(void)arg;
|
(void)arg;
|
||||||
return 0;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
cthread_t thread;
|
cthread_t thread;
|
||||||
int rc = cthread_create(&thread, NULL, &worker, NULL);
|
int rc = cthread_create(&thread, NULL, &worker, NULL);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
printf("thread created: %p\n", thread);
|
//printf("thread created: %p\n", thread);
|
||||||
sleep(1000);
|
sleep(1);
|
||||||
|
#if 1
|
||||||
|
cthread_join(thread, &rc);
|
||||||
|
#else
|
||||||
|
rc = cthread_detach(thread);
|
||||||
|
sleep(2);
|
||||||
|
#endif
|
||||||
|
//printf("thread joined: %p -> %d\n", thread, rc);
|
||||||
} else {
|
} else {
|
||||||
printf("ERROR: thread could not be started: %d\n", rc);
|
printf("ERROR: thread could not be started: %d\n", rc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "libc/thread/create.h"
|
#include "libc/thread/create.h"
|
||||||
#include "libc/linux/clone.h"
|
#include "libc/linux/clone.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/linux/mmap.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
#include "libc/sysv/consts/clone.h"
|
#include "libc/sysv/consts/clone.h"
|
||||||
#include "libc/sysv/consts/map.h"
|
#include "libc/sysv/consts/map.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
static cthread_t _thread_allocate(const cthread_attr_t* attr) {
|
static cthread_t _thread_allocate(const cthread_attr_t* attr) {
|
||||||
size_t stacksize = attr->stacksize;
|
size_t stacksize = attr->stacksize;
|
||||||
size_t guardsize = 0;//attr->guardsize;
|
size_t guardsize = attr->guardsize;
|
||||||
// FIXME: properly count TLS size
|
// FIXME: properly count TLS size
|
||||||
size_t tlssize = 0;
|
size_t tlssize = 0;
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ static cthread_t _thread_allocate(const cthread_attr_t* attr) {
|
||||||
td->tls.bottom = tls_bottom;
|
td->tls.bottom = tls_bottom;
|
||||||
td->alloc.top = alloc_top;
|
td->alloc.top = alloc_top;
|
||||||
td->alloc.bottom = alloc_bottom;
|
td->alloc.bottom = alloc_bottom;
|
||||||
td->tid = 0;
|
td->state = (attr->mode & CTHREAD_CREATE_DETACHED) ? cthread_detached : cthread_started;
|
||||||
|
|
||||||
return td;
|
return td;
|
||||||
}
|
}
|
||||||
|
@ -68,41 +68,41 @@ int cthread_create(cthread_t*restrict p, const cthread_attr_t*restrict attr, int
|
||||||
extern wontreturn void _thread_run(int(*func)(void*), void* arg);
|
extern wontreturn void _thread_run(int(*func)(void*), void* arg);
|
||||||
|
|
||||||
cthread_attr_t default_attr;
|
cthread_attr_t default_attr;
|
||||||
if (!attr) cthread_attr_init(&default_attr);
|
cthread_attr_init(&default_attr);
|
||||||
cthread_t td = _thread_allocate(attr ? attr : &default_attr);
|
cthread_t td = _thread_allocate(attr ? attr : &default_attr);
|
||||||
if (!attr) cthread_attr_destroy(&default_attr);
|
cthread_attr_destroy(&default_attr);
|
||||||
if (!td) return errno;
|
if (!td) return errno;
|
||||||
|
|
||||||
*p = td;
|
*p = td;
|
||||||
|
|
||||||
uintptr_t stack = (uintptr_t)(td->stack.top);
|
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;
|
||||||
|
|
||||||
stack -= sizeof(void*); *(void**)stack = func;
|
long flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_PARENT | CLONE_THREAD | /*CLONE_IO |*/ CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
|
||||||
stack -= sizeof(void*); *(void**)stack = arg;
|
int rc;
|
||||||
|
// asm ensures the (empty) stack of the child thread is not used
|
||||||
long flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_PARENT | CLONE_THREAD | /*CLONE_IO |*/ CLONE_SETTLS;
|
|
||||||
|
|
||||||
// It is not necessary to check the return of the syscall here as the return address for the thread is setup to to `_thread_run`.
|
|
||||||
// In case of success: the parent callee returns immediately to the caller forwarding the success to the callee
|
|
||||||
// the child return immediately to the entry point of `thread_spawn`
|
|
||||||
// In case of error: the parent callee returns immediately to the caller forwarding the error
|
|
||||||
// the child is never created (and so cannot returned in the wrong place)
|
|
||||||
int rc = LinuxClone(flags, (void*)stack, NULL, NULL, (void*)td);
|
|
||||||
if (!rc) {
|
|
||||||
// child
|
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"xor %rbp,%rbp\n\t"
|
"syscall\n\t" // clone
|
||||||
/* pop arguments */
|
"test\t%0, %0\n\t" // if not child
|
||||||
"pop %rdi\n\t"
|
"jne\t.L.cthread_create.%=\n\t" // jump to `parent` label
|
||||||
"pop %rax\n\t"
|
"xor\t%%rbp, %%rbp\n\t" // reset stack frame pointer
|
||||||
/* call function */
|
"mov\t%2, %%rdi\n\t"
|
||||||
"call *%rax\n\t"
|
"call\t*%1\n\t" // call `func(arg)`
|
||||||
/* thread exit */
|
"mov\t%%rax, %%rdi\n\t"
|
||||||
"mov %rax, %rdi\n\t"
|
"jmp\tcthread_exit\n" // exit thread
|
||||||
"jmp cthread_exit"
|
".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"
|
||||||
);
|
);
|
||||||
unreachable;
|
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;
|
||||||
}
|
}
|
||||||
if (rc < 0) return rc;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_THREAD_CREATE_H_
|
#ifndef COSMOPOLITAN_LIBC_THREAD_CREATE_H_
|
||||||
#define 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)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview thread
|
* @fileoverview Create a cosmopolitan thread
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "libc/thread/attr.h"
|
|
||||||
#include "libc/thread/descriptor.h"
|
|
||||||
|
|
||||||
int cthread_create(cthread_t*restrict, const cthread_attr_t*restrict, int (*)(void*), void*restrict);
|
int cthread_create(cthread_t*restrict, const cthread_attr_t*restrict, int (*)(void*), void*restrict);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,23 @@ COSMOPOLITAN_C_START_
|
||||||
* @fileoverview thread types
|
* @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 {
|
||||||
struct cthread_descriptor_t* self; // mandatory for TLS
|
struct cthread_descriptor_t* self; // mandatory for TLS
|
||||||
struct {
|
struct {
|
||||||
void *top, *bottom;
|
void *top, *bottom;
|
||||||
} stack, tls, alloc;
|
} stack, tls, alloc;
|
||||||
|
int state;
|
||||||
int tid;
|
int tid;
|
||||||
|
int rc;
|
||||||
|
void* pthread_ret_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct cthread_descriptor_t* cthread_t;
|
typedef struct cthread_descriptor_t* cthread_t;
|
||||||
|
|
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_ */
|
||||||
|
|
|
@ -17,30 +17,28 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/thread/exit.h"
|
#include "libc/thread/exit.h"
|
||||||
|
#include "libc/thread/self.h"
|
||||||
#include "libc/thread/descriptor.h"
|
#include "libc/thread/descriptor.h"
|
||||||
#include "libc/linux/munmap.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
|
|
||||||
static wontreturn void _self_exit(void* p, size_t s, int r) {
|
wontreturn void cthread_exit(int rc) {
|
||||||
// asm is necessary as the stack does not exist between the unmap and the actual exit
|
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(
|
asm volatile(
|
||||||
"mov $11, %%rax\n\t"
|
"lock xadd\t%1, %0\n\t" // mark thread as finished
|
||||||
"syscall\n\t"
|
"test\t%2, %b1\n\t" // test if thread was detached
|
||||||
"mov %%rbx, %%rdi\n\t"
|
"jz .L.cthread_exit.%=\n\t" // skip unmap if not detached
|
||||||
"mov $60, %%rax\n\t"
|
"syscall\n" // unmap thread
|
||||||
"syscall"
|
".L.cthread_exit.%=:\n\t"
|
||||||
:
|
"mov\t%%rbx, %%rdi\n\t" //rc
|
||||||
: "D"(p), "S"(s), "b"(r)
|
"mov\t$60, %%rax\n\t"
|
||||||
: "memory"
|
"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;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
wontreturn void cthread_exit(int rc) {
|
|
||||||
// TODO: wait joiners
|
|
||||||
|
|
||||||
cthread_t td;
|
|
||||||
asm("mov %%fs:0, %0" : "=r"(td));
|
|
||||||
size_t size = (intptr_t)(td->alloc.top) - (intptr_t)(td->alloc.bottom);
|
|
||||||
|
|
||||||
_self_exit(td->alloc.top, size, rc);
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview internal function called after a thread exits
|
* @fileoverview exit the current thread
|
||||||
*/
|
*/
|
||||||
|
|
||||||
wontreturn void cthread_exit(int);
|
wontreturn void cthread_exit(int);
|
||||||
|
|
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;
|
||||||
|
}
|
16
libc/thread/join.h
Normal file
16
libc/thread/join.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#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_ */
|
||||||
|
|
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_ */
|
Loading…
Add table
Add a link
Reference in a new issue