+ __block_app_sigs(&set);
+
+ /* This atomic potentially competes with a concurrent pthread_detach
+ * call; the loser is responsible for freeing thread resources. */
+ int state = a_cas(&self->detach_state, DT_JOINABLE, DT_EXITING);
+
+ if (state==DT_DETACHED && self->map_base) {
+ /* Since __unmapself bypasses the normal munmap code path,
+ * explicitly wait for vmlock holders first. This must be
+ * done before any locks are taken, to avoid lock ordering
+ * issues that could lead to deadlock. */
+ __vm_wait();
+ }
+
+ /* Access to target the exiting thread with syscalls that use
+ * its kernel tid is controlled by killlock. For detached threads,
+ * any use past this point would have undefined behavior, but for
+ * joinable threads it's a valid usage that must be handled.
+ * Signals must be blocked since pthread_kill must be AS-safe. */
+ LOCK(self->killlock);
+
+ /* The thread list lock must be AS-safe, and thus depends on
+ * application signals being blocked above. */
+ __tl_lock();
+
+ /* If this is the only thread in the list, don't proceed with
+ * termination of the thread, but restore the previous lock and
+ * signal state to prepare for exit to call atexit handlers. */
+ if (self->next == self) {
+ __tl_unlock();
+ UNLOCK(self->killlock);
+ self->detach_state = state;
+ __restore_sigs(&set);
+ exit(0);
+ }
+
+ /* At this point we are committed to thread termination. */
+
+ /* After the kernel thread exits, its tid may be reused. Clear it
+ * to prevent inadvertent use and inform functions that would use
+ * it that it's no longer available. At this point the killlock
+ * may be released, since functions that use it will consistently
+ * see the thread as having exited. Release it now so that no
+ * remaining locks (except thread list) are held if we end up
+ * resetting need_locks below. */
+ self->tid = 0;
+ UNLOCK(self->killlock);