blob: fad195b1f42233b3c6bcd17daab2576d60f7bf73 [file] [log] [blame] [edit]
// Copyright 2025 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <atomic>
#include "libc.h"
#include "src/stdlib/exit.h"
#include "thread.h"
#include "threads_impl.h"
namespace LIBC_NAMESPACE_DECL {
// This is replaced with a real definition when dlerror() code is linked in.
[[gnu::weak]] void ThreadDlfcnCleanup() {}
// This does the final "normal" work on the exiting thread: running
// destructors, etc. This is reached either directly from a call to
// thrd_exit() or pthread_exit(), or from a thread function returning.
[[noreturn]] void ThreadExit(intptr_t value) {
__tls_run_dtors(); // Run C++ thread_local destructors.
__thread_tsd_run_dtors(); // Run tss_create / pthread_key_create destructors.
// It's impossible to determine whether this is "the last thread" until
// performing the atomic decrement, since multiple threads could exit at the
// same time. If it was the last thread, then the whole process exits.
if (__libc.thread_count.fetch_sub(1) == 1) {
// The old value was one, so now the value is zero: this is the last thread
// and should call exit(0). But first, put the thread count back to one,
// "undoing" the thread exit to return to being a normal single-threaded
// process while executing the process exit. The atexit handlers could do
// anything, including starting new threads or even reentering here after
// new threads might be waiting to join this one!
__libc.thread_count.store(1);
exit(0);
}
// Finally, no more user code will run on this thread and call back into
// libc, e.g. dlerror(). Clean up any allocation stored for dlerror().
ThreadDlfcnCleanup();
// Store the value for ThreadJoin() to find. Any joiners already waiting
// will be woken via futex last thing in ThreadExitFinish().
Thread& self = *__pthread_self();
self.join_value = value;
// After this point the sanitizer runtime will tear down its state, so we
// cannot run any more sanitized code. The rest is done in code compiled for
// the basic machine ABI.
ThreadExitFinish(self);
}
} // namespace LIBC_NAMESPACE_DECL