blob: 4f9ef77256436c304cff0a18b904a450f7454644 [file] [log] [blame]
// 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 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();
__thread_tsd_run_dtors();
__dl_thread_cleanup();
// 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) == 0) {
// 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);
}
// 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