mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-07 10:20:29 +00:00
Proper thread creation and exit
This commit is contained in:
parent
149b1901b0
commit
fb2dd3ff89
11 changed files with 305 additions and 141 deletions
|
@ -8,7 +8,8 @@
|
|||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/create.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
int worker(void* arg) {
|
||||
(void)arg;
|
||||
|
@ -16,13 +17,13 @@ int worker(void* arg) {
|
|||
}
|
||||
|
||||
int main() {
|
||||
thread_descriptor_t* thread = allocate_thread();
|
||||
|
||||
if (thread) {
|
||||
long rc = start_thread(thread, &worker, NULL);
|
||||
printf("thread created: %ld\n", rc);
|
||||
cthread_t thread;
|
||||
int rc = cthread_create(&thread, NULL, &worker, NULL);
|
||||
if (rc == 0) {
|
||||
printf("thread created: %p\n", thread);
|
||||
sleep(1000);
|
||||
} else {
|
||||
printf("ERROR: thread stack could not be allocated\n");
|
||||
printf("ERROR: thread could not be started: %d\n", rc);
|
||||
}
|
||||
return 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/linux/mmap.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 = 0;//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->tid = 0;
|
||||
|
||||
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;
|
||||
if (!attr) cthread_attr_init(&default_attr);
|
||||
cthread_t td = _thread_allocate(attr ? attr : &default_attr);
|
||||
if (!attr) cthread_attr_destroy(&default_attr);
|
||||
if (!td) return errno;
|
||||
|
||||
*p = td;
|
||||
|
||||
uintptr_t stack = (uintptr_t)(td->stack.top);
|
||||
|
||||
stack -= sizeof(void*); *(void**)stack = func;
|
||||
stack -= sizeof(void*); *(void**)stack = arg;
|
||||
|
||||
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(
|
||||
"xor %rbp,%rbp\n\t"
|
||||
/* pop arguments */
|
||||
"pop %rdi\n\t"
|
||||
"pop %rax\n\t"
|
||||
/* call function */
|
||||
"call *%rax\n\t"
|
||||
/* thread exit */
|
||||
"mov %rax, %rdi\n\t"
|
||||
"jmp cthread_exit"
|
||||
);
|
||||
unreachable;
|
||||
}
|
||||
if (rc < 0) return rc;
|
||||
return 0;
|
||||
}
|
18
libc/thread/create.h
Normal file
18
libc/thread/create.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_CREATE_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_CREATE_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview 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);
|
||||
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_CREATE_H_ */
|
22
libc/thread/descriptor.h
Normal file
22
libc/thread/descriptor.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview thread types
|
||||
*/
|
||||
|
||||
struct cthread_descriptor_t {
|
||||
struct cthread_descriptor_t* self; // mandatory for TLS
|
||||
struct {
|
||||
void *top, *bottom;
|
||||
} stack, tls, alloc;
|
||||
int tid;
|
||||
};
|
||||
|
||||
typedef struct cthread_descriptor_t* cthread_t;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_DESCRIPTOR_H_ */
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
/*-*- 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 │
|
||||
│ │
|
||||
|
@ -16,38 +16,31 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/thread/exit.h"
|
||||
#include "libc/thread/descriptor.h"
|
||||
#include "libc/linux/munmap.h"
|
||||
|
||||
// wontreturn void thread_spawn(int(*func)(void*), void* arg);
|
||||
//
|
||||
// This function is the root function of a new thread.
|
||||
// It calls `func` with `arg`.
|
||||
// The return value of `func` is passed as argument to the `exit` syscall.
|
||||
//
|
||||
// All arguments are passed onto the (newly created) stack.
|
||||
// The stack must have been set as followed:
|
||||
// Top
|
||||
// +------------+
|
||||
// | func |
|
||||
// +------------+
|
||||
// | arg |
|
||||
// %rsp -> +------------+
|
||||
//
|
||||
static wontreturn void _self_exit(void* p, size_t s, int r) {
|
||||
// asm is necessary as the stack does not exist between the unmap and the actual exit
|
||||
asm volatile(
|
||||
"mov $11, %%rax\n\t"
|
||||
"syscall\n\t"
|
||||
"mov %%rbx, %%rdi\n\t"
|
||||
"mov $60, %%rax\n\t"
|
||||
"syscall"
|
||||
:
|
||||
: "D"(p), "S"(s), "b"(r)
|
||||
: "memory"
|
||||
);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
thread_spawn:
|
||||
.cfi_startproc
|
||||
/* stop stack trace from going deeper than this function */
|
||||
.cfi_undefined rip
|
||||
xor %rbp,%rbp
|
||||
/* pop arguments */
|
||||
pop %rdi
|
||||
pop %rax
|
||||
/* call function */
|
||||
call *%rax
|
||||
/* thread exit */
|
||||
mov %rax, %rdi
|
||||
mov 60, %rax
|
||||
syscall
|
||||
.cfi_endproc
|
||||
.endfn thread_spawn,globl
|
||||
.source __FILE__
|
||||
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);
|
||||
}
|
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 internal function called after a thread exits
|
||||
*/
|
||||
|
||||
wontreturn void cthread_exit(int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_EXIT_H_ */
|
|
@ -1,79 +0,0 @@
|
|||
/*-*- 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/thread.h"
|
||||
#include "libc/linux/mmap.h"
|
||||
#include "libc/linux/clone.h"
|
||||
|
||||
// sched.h
|
||||
#define CLONE_VM 0x00000100
|
||||
#define CLONE_FS 0x00000200
|
||||
#define CLONE_FILES 0x00000400
|
||||
#define CLONE_SIGHAND 0x00000800
|
||||
#define CLONE_PARENT 0x00008000
|
||||
#define CLONE_THREAD 0x00010000
|
||||
#define CLONE_SETTLS 0x00080000
|
||||
#define CLONE_IO 0x80000000
|
||||
|
||||
// sys/mman.h
|
||||
#define MAP_GROWSDOWN 0x0100
|
||||
#define MAP_ANONYMOUS 0x0020
|
||||
#define MAP_PRIVATE 0x0002
|
||||
#define PROT_READ 0x1
|
||||
#define PROT_WRITE 0x2
|
||||
#define PROT_EXEC 0x4
|
||||
|
||||
|
||||
thread_descriptor_t* allocate_thread() {
|
||||
const long pagesize = 4096;
|
||||
long stacksize = 1024*pagesize;
|
||||
// FIXME: properly count TLS size
|
||||
long tlssize = 0;
|
||||
long totalsize = stacksize + tlssize + sizeof(thread_descriptor_t);
|
||||
|
||||
// round-up totalsize to pagesize
|
||||
totalsize = (totalsize + pagesize-1) & -pagesize;
|
||||
|
||||
intptr_t mem = LinuxMmap(NULL, totalsize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
if (mem == -1) return NULL;
|
||||
|
||||
thread_descriptor_t* descriptor = (thread_descriptor_t*)(mem + totalsize - sizeof(thread_descriptor_t));
|
||||
descriptor->self = descriptor; // setup TLS (System-V ABI)
|
||||
descriptor->stack = (void*)(mem + stacksize);
|
||||
|
||||
// FIXME: properly copy .tdata
|
||||
return descriptor;
|
||||
}
|
||||
long start_thread(thread_descriptor_t* descriptor, int (*func)(void*), void* arg) {
|
||||
extern wontreturn void thread_spawn(int(*func)(void*), void* arg);
|
||||
|
||||
// Set-up thread stack
|
||||
uintptr_t stack = (uintptr_t)(descriptor->stack) - 3*sizeof(void*);
|
||||
*(void**)(stack + 2*sizeof(void*)) = func;
|
||||
*(void**)(stack + 1*sizeof(void*)) = arg;
|
||||
*(void**)(stack + 0*sizeof(void*)) = &thread_spawn;
|
||||
|
||||
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_spawn`.
|
||||
// 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)
|
||||
return LinuxClone(flags, (void*)stack, NULL, NULL, descriptor);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_THREAD_THREAD_H_
|
||||
#define COSMOPOLITAN_LIBC_THREAD_THREAD_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview thread
|
||||
*/
|
||||
|
||||
typedef struct thread_descriptor_t {
|
||||
struct thread_descriptor_t* self; // mandatory for TLS
|
||||
void* stack;
|
||||
} thread_descriptor_t;
|
||||
|
||||
thread_descriptor_t* allocate_thread();
|
||||
long start_thread(thread_descriptor_t*, int (*)(void*), void*);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_THREAD_H_ */
|
|
@ -25,8 +25,12 @@ LIBC_THREAD_A_CHECKS = \
|
|||
|
||||
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 := \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue