mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 05:42:29 +00:00
Make _Thread_local work across platforms
We now rewrite the binary image at runtime on Windows and XNU to change mov %fs:0,%reg instructions to use %gs instead. There's also simpler threading API introduced by this change and it's called _spawn() and _join(), which has replaced most clone() usage.
This commit is contained in:
parent
e4d6e263d4
commit
5f4f6b0e69
51 changed files with 808 additions and 1043 deletions
|
@ -23,9 +23,11 @@
|
|||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/intrin/wait0.internal.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
@ -36,10 +38,10 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/spawn.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
char *stack, *tls;
|
||||
int x, me, tid, *childetid;
|
||||
int x, me, tid;
|
||||
_Atomic(int) thechilde;
|
||||
|
||||
__attribute__((__constructor__)) static void init(void) {
|
||||
|
@ -47,47 +49,38 @@ __attribute__((__constructor__)) static void init(void) {
|
|||
errno = 0;
|
||||
}
|
||||
|
||||
void *__initialize_tls(char tib[64]) {
|
||||
if (tib) {
|
||||
*(intptr_t *)(tib + 0x00) = (intptr_t)tib;
|
||||
*(intptr_t *)(tib + 0x30) = (intptr_t)tib;
|
||||
*(int *)(tib + 0x38) = -1; // tid
|
||||
*(int *)(tib + 0x3c) = 0;
|
||||
}
|
||||
return tib;
|
||||
}
|
||||
|
||||
void SetUp(void) {
|
||||
x = 0;
|
||||
me = gettid();
|
||||
tls = calloc(1, 64);
|
||||
__initialize_tls(tls);
|
||||
*(int *)(tls + 0x3c) = 31337;
|
||||
childetid = (int *)(tls + 0x38);
|
||||
ASSERT_NE(MAP_FAILED, (stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_STACK | MAP_ANONYMOUS, -1, 0)));
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
EXPECT_SYS(0, 0, munmap(stack, GetStackSize()));
|
||||
free(tls);
|
||||
}
|
||||
|
||||
int DoNothing(void *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TEST ERROR NUMBERS
|
||||
|
||||
TEST(clone, testNullFunc_raisesEinval) {
|
||||
EXPECT_SYS(EINVAL, -1,
|
||||
clone(0, stack, GetStackSize(),
|
||||
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
|
||||
CLONE_SIGHAND | CLONE_SETTLS,
|
||||
0, 0, tls, 64, 0));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TEST THREADS WORK
|
||||
|
||||
int CloneTest1(void *arg) {
|
||||
int CloneTest1(void *arg, int tid) {
|
||||
intptr_t rsp, top, bot;
|
||||
CheckStackIsAligned();
|
||||
// PrintBacktraceUsingSymbols(2, __builtin_frame_address(0),
|
||||
// GetSymbolTable());
|
||||
rsp = (intptr_t)__builtin_frame_address(0);
|
||||
bot = (intptr_t)stack;
|
||||
bot = ROUNDDOWN((intptr_t)rsp, GetStackSize());
|
||||
top = bot + GetStackSize();
|
||||
ASSERT_GT(rsp, bot); // check we're on stack
|
||||
ASSERT_LT(rsp, top); // check we're on stack
|
||||
|
@ -95,28 +88,16 @@ int CloneTest1(void *arg) {
|
|||
ASSERT_TRUE(IS2POW(GetStackSize()));
|
||||
ASSERT_EQ(0, bot & (GetStackSize() - 1));
|
||||
x = 42;
|
||||
if (!IsWindows()) {
|
||||
ASSERT_EQ(31337, errno);
|
||||
} else {
|
||||
errno = 31337;
|
||||
ASSERT_EQ(31337, errno);
|
||||
}
|
||||
ASSERT_EQ(23, (intptr_t)arg);
|
||||
ASSERT_NE(gettid(), getpid());
|
||||
ASSERT_EQ(gettid(), *childetid); // CLONE_CHILD_SETTID
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(clone, test1) {
|
||||
int ptid = 0;
|
||||
*childetid = -1;
|
||||
ASSERT_NE(-1, (tid = clone(CloneTest1, stack, GetStackSize(),
|
||||
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
|
||||
CLONE_SIGHAND | CLONE_PARENT_SETTID |
|
||||
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID |
|
||||
CLONE_SETTLS,
|
||||
(void *)23, &ptid, tls, 64, childetid)));
|
||||
_wait0(childetid); // CLONE_CHILD_CLEARTID
|
||||
struct spawn th;
|
||||
ASSERT_SYS(0, 0, _spawn(CloneTest1, (void *)23, &th));
|
||||
ASSERT_SYS(0, 0, _join(&th));
|
||||
ASSERT_NE(gettid(), tid);
|
||||
ASSERT_EQ(tid, ptid);
|
||||
ASSERT_EQ(42, x);
|
||||
|
@ -132,7 +113,7 @@ TEST(clone, test1) {
|
|||
|
||||
_Atomic(int) sysbarrier;
|
||||
|
||||
int CloneTestSys(void *arg) {
|
||||
int CloneTestSys(void *arg, int tid) {
|
||||
int i, id = (intptr_t)arg;
|
||||
CheckStackIsAligned();
|
||||
while (!sysbarrier) asm("pause");
|
||||
|
@ -165,25 +146,14 @@ int CloneTestSys(void *arg) {
|
|||
|
||||
TEST(clone, tlsSystemCallsErrno_wontClobberMainThreadBecauseTls) {
|
||||
int i;
|
||||
char *tls[8], *stack[8];
|
||||
struct spawn th[8];
|
||||
ASSERT_EQ(0, errno);
|
||||
for (i = 0; i < 8; ++i) {
|
||||
tls[i] = __initialize_tls(malloc(64));
|
||||
stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_STACK | MAP_ANONYMOUS, -1, 0);
|
||||
ASSERT_NE(
|
||||
-1,
|
||||
(tid = clone(
|
||||
CloneTestSys, stack[i], GetStackSize(),
|
||||
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
||||
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS,
|
||||
(void *)(intptr_t)i, 0, tls[i], 64, (int *)(tls[i] + 0x38))));
|
||||
ASSERT_SYS(0, 0, _spawn(CloneTestSys, (void *)(intptr_t)i, th + i));
|
||||
}
|
||||
sysbarrier = 1;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
_wait0((int *)(tls[i] + 0x38));
|
||||
free(tls[i]);
|
||||
munmap(stack[i], GetStackSize());
|
||||
ASSERT_SYS(0, 0, _join(th + i));
|
||||
}
|
||||
ASSERT_EQ(0, errno);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue