mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-27 04:50:28 +00:00
Get threads working on all platforms
We now have a high-quality clone() implementation for creating lightweight threads on Linux/Windows/FreeBSD/NetBSD/OpenBSD.
This commit is contained in:
parent
4e62cefa6e
commit
fec396037a
43 changed files with 850 additions and 532 deletions
|
@ -16,14 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/setjmp.internal.h"
|
||||
#include "libc/intrin/winthread.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
||||
/**
|
||||
|
@ -36,18 +34,15 @@
|
|||
*/
|
||||
privileged wontreturn void _Exit1(int rc) {
|
||||
struct WinThread *wt;
|
||||
STRACE("_Exit1(%d)", rc);
|
||||
/* STRACE("_Exit1(%d)", rc); */
|
||||
if (!IsWindows() && !IsMetal()) {
|
||||
register long r10 asm("r10") = 0;
|
||||
asm volatile("syscall"
|
||||
: /* no outputs */
|
||||
: "a"(__NR_exit), "D"(IsLinux() ? rc : 0)
|
||||
: "a"(__NR_exit), "D"(IsLinux() ? rc : 0), "S"(0), "d"(0),
|
||||
"r"(r10)
|
||||
: "rcx", "r11", "memory");
|
||||
__builtin_unreachable();
|
||||
} else if (IsWindows()) {
|
||||
if ((wt = GetWinThread())) {
|
||||
__releasefd(wt->pid);
|
||||
weaken(free)(wt);
|
||||
}
|
||||
ExitThread(rc);
|
||||
}
|
||||
for (;;) {
|
||||
|
|
|
@ -19,18 +19,21 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/tls.h"
|
||||
#include "libc/intrin/winthread.internal.h"
|
||||
#include "libc/nt/thread.h"
|
||||
|
||||
/**
|
||||
* Returns current thread id.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int gettid(void) {
|
||||
privileged int gettid(void) {
|
||||
int rc;
|
||||
int64_t wut;
|
||||
struct WinThread *wt;
|
||||
|
||||
if (IsWindows()) {
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
|
||||
if (IsLinux()) {
|
||||
asm("syscall"
|
||||
: "=a"(rc) // man says always succeeds
|
||||
|
@ -59,7 +62,7 @@ int gettid(void) {
|
|||
asm("syscall"
|
||||
: "=a"(rc) // man says always succeeds
|
||||
: "0"(311) // _lwp_self()
|
||||
: "rcx", "r11", "memory", "cc");
|
||||
: "rcx", "rdx", "r11", "memory", "cc");
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -73,13 +76,5 @@ int gettid(void) {
|
|||
return wut; // narrowing intentional
|
||||
}
|
||||
|
||||
if (IsWindows()) {
|
||||
if ((wt = GetWinThread())) {
|
||||
return wt->pid;
|
||||
} else {
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
}
|
||||
|
||||
return getpid();
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/threaded.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -56,7 +57,6 @@ struct Timestamps {
|
|||
unsigned long long start;
|
||||
};
|
||||
|
||||
extern bool __threaded;
|
||||
unsigned long long __kbirth; // see fork-nt.c
|
||||
|
||||
privileged static struct Timestamps kenter(void) {
|
||||
|
|
29
libc/intrin/setjmp.internal.h
Normal file
29
libc/intrin/setjmp.internal.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_SETJMP_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_SETJMP_INTERNAL_H_
|
||||
#include "libc/limits.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* Encodes nonzero number for longjmp().
|
||||
*
|
||||
* This is a workaround to the fact that the value has to be non-zero.
|
||||
* So we work around it by dedicating the highest bit to being a flag.
|
||||
*/
|
||||
static inline int EncodeLongjmp(int x) {
|
||||
return x | INT_MIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes nonzero number returned by setjmp().
|
||||
*
|
||||
* This is a workaround to the fact that the value has to be non-zero.
|
||||
* So we work around it by dedicating the highest bit to being a flag.
|
||||
*/
|
||||
static inline int DecodeSetjmp(int x) {
|
||||
return (int)((unsigned)x << 1) >> 1;
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_SETJMP_INTERNAL_H_ */
|
|
@ -2,27 +2,33 @@
|
|||
#define COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
|
||||
|
||||
#ifdef TINY
|
||||
#define _spinlock(lock) \
|
||||
do { \
|
||||
while (__sync_lock_test_and_set(lock, 1)) { \
|
||||
__builtin_ia32_pause(); \
|
||||
} \
|
||||
#define _spinlock(lock) \
|
||||
do { \
|
||||
while (__atomic_test_and_set(lock, __ATOMIC_SEQ_CST)) { \
|
||||
__builtin_ia32_pause(); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define _spinlock(lock) \
|
||||
do { \
|
||||
for (;;) { \
|
||||
typeof(*(lock)) x; \
|
||||
__atomic_load(lock, &x, __ATOMIC_RELAXED); \
|
||||
if (!x && !__sync_lock_test_and_set(lock, 1)) { \
|
||||
break; \
|
||||
} else { \
|
||||
__builtin_ia32_pause(); \
|
||||
} \
|
||||
} \
|
||||
#define _spinlock(lock) \
|
||||
do { \
|
||||
for (;;) { \
|
||||
typeof(*(lock)) x; \
|
||||
__atomic_load(lock, &x, __ATOMIC_RELAXED); \
|
||||
if (!x && !__atomic_test_and_set(lock, __ATOMIC_SEQ_CST)) { \
|
||||
break; \
|
||||
} else { \
|
||||
__builtin_ia32_pause(); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define _spunlock(lock) __sync_lock_release(lock)
|
||||
#define _spunlock(lock) __atomic_clear(lock, __ATOMIC_RELAXED)
|
||||
|
||||
#define _seizelock(lock) \
|
||||
do { \
|
||||
typeof(*(lock)) x = 1; \
|
||||
__atomic_store(lock, &x, __ATOMIC_SEQ_CST); \
|
||||
} while (0)
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ */
|
||||
|
|
|
@ -16,5 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/threaded.internal.h"
|
||||
|
||||
bool __threaded;
|
||||
|
|
10
libc/intrin/threaded.internal.h
Normal file
10
libc/intrin/threaded.internal.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_THREADED_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_THREADED_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern bool __threaded;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_THREADED_INTERNAL_H_ */
|
|
@ -1,11 +1,16 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_RUNTIME_WINTHREAD_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_RUNTIME_WINTHREAD_INTERNAL_H_
|
||||
#include "libc/intrin/tls.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct WinThread {
|
||||
int pid;
|
||||
uint32_t tid;
|
||||
int flags;
|
||||
int *ctid;
|
||||
int (*func)(void *);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
extern int __winthread;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue