Skip to content

Commit e72ad3c

Browse files
committed
tsan: use semaphores for thread creation synchronization
We currently use ad-hoc spin waiting to synchronize thread creation and thread start both ways. But spinning tend to degrade ungracefully under high contention (lots of threads are created at the same time). Use semaphores for synchronization instead. Reviewed By: melver Differential Revision: https://reviews.llvm.org/D107337
1 parent 977bdf6 commit e72ad3c

File tree

1 file changed

+11
-12
lines changed

1 file changed

+11
-12
lines changed

compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -933,14 +933,15 @@ static void thread_finalize(void *v) {
933933
struct ThreadParam {
934934
void* (*callback)(void *arg);
935935
void *param;
936-
atomic_uintptr_t tid;
936+
Tid tid;
937+
Semaphore created;
938+
Semaphore started;
937939
};
938940

939941
extern "C" void *__tsan_thread_start_func(void *arg) {
940942
ThreadParam *p = (ThreadParam*)arg;
941943
void* (*callback)(void *arg) = p->callback;
942944
void *param = p->param;
943-
int tid = 0;
944945
{
945946
cur_thread_init();
946947
ThreadState *thr = cur_thread();
@@ -955,12 +956,11 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
955956
}
956957
ThreadIgnoreEnd(thr);
957958
#endif
958-
while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
959-
internal_sched_yield();
959+
p->created.Wait();
960960
Processor *proc = ProcCreate();
961961
ProcWire(proc, thr);
962-
ThreadStart(thr, tid, GetTid(), ThreadType::Regular);
963-
atomic_store(&p->tid, 0, memory_order_release);
962+
ThreadStart(thr, p->tid, GetTid(), ThreadType::Regular);
963+
p->started.Post();
964964
}
965965
void *res = callback(param);
966966
// Prevent the callback from being tail called,
@@ -999,7 +999,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
999999
ThreadParam p;
10001000
p.callback = callback;
10011001
p.param = param;
1002-
atomic_store(&p.tid, 0, memory_order_relaxed);
1002+
p.tid = kMainTid;
10031003
int res = -1;
10041004
{
10051005
// Otherwise we see false positives in pthread stack manipulation.
@@ -1009,18 +1009,17 @@ TSAN_INTERCEPTOR(int, pthread_create,
10091009
ThreadIgnoreEnd(thr);
10101010
}
10111011
if (res == 0) {
1012-
Tid tid = ThreadCreate(thr, pc, *(uptr *)th, IsStateDetached(detached));
1013-
CHECK_NE(tid, kMainTid);
1012+
p.tid = ThreadCreate(thr, pc, *(uptr *)th, IsStateDetached(detached));
1013+
CHECK_NE(p.tid, kMainTid);
10141014
// Synchronization on p.tid serves two purposes:
10151015
// 1. ThreadCreate must finish before the new thread starts.
10161016
// Otherwise the new thread can call pthread_detach, but the pthread_t
10171017
// identifier is not yet registered in ThreadRegistry by ThreadCreate.
10181018
// 2. ThreadStart must finish before this thread continues.
10191019
// Otherwise, this thread can call pthread_detach and reset thr->sync
10201020
// before the new thread got a chance to acquire from it in ThreadStart.
1021-
atomic_store(&p.tid, tid, memory_order_release);
1022-
while (atomic_load(&p.tid, memory_order_acquire) != 0)
1023-
internal_sched_yield();
1021+
p.created.Post();
1022+
p.started.Wait();
10241023
}
10251024
if (attr == &myattr)
10261025
pthread_attr_destroy(&myattr);

0 commit comments

Comments
 (0)