| // 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 |