1 /* Thread termination.
2    Copyright (C) 2000-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library;  if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <assert.h>
20 #include <errno.h>
21 #include <pthread.h>
22 #include <stdlib.h>
23 
24 #include <pt-internal.h>
25 #include <pthreadP.h>
26 
27 #include <atomic.h>
28 
29 
30 /* Terminate the current thread and make STATUS available to any
31    thread that might join it.  */
32 void
__pthread_exit(void * status)33 __pthread_exit (void *status)
34 {
35   struct __pthread *self = _pthread_self ();
36   struct __pthread_cancelation_handler **handlers;
37   int oldstate;
38 
39   /* Run any cancelation handlers.  According to POSIX, the
40      cancellation cleanup handlers should be called with cancellation
41      disabled.  */
42   __pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
43 
44   for (handlers = __pthread_get_cleanup_stack ();
45        *handlers != NULL;
46        *handlers = (*handlers)->__next)
47     (*handlers)->__handler ((*handlers)->__arg);
48 
49   __pthread_setcancelstate (oldstate, &oldstate);
50 
51   /* Decrease the number of threads.  We use an atomic operation to
52      make sure that only the last thread calls `exit'.  */
53   if (atomic_decrement_and_test (&__pthread_total))
54     /* We are the last thread.  */
55     exit (0);
56 
57   /* Destroy any thread specific data.  */
58   __pthread_destroy_specific (self);
59 
60   /* Note that after this point the process can be terminated at any
61      point if another thread calls `pthread_exit' and happens to be
62      the last thread.  */
63 
64   __pthread_mutex_lock (&self->state_lock);
65 
66   if (self->cancel_state == PTHREAD_CANCEL_ENABLE && self->cancel_pending)
67     status = PTHREAD_CANCELED;
68 
69   switch (self->state)
70     {
71     default:
72       assert (!"Consistency error: unexpected self->state");
73       abort ();
74       break;
75 
76     case PTHREAD_DETACHED:
77       __pthread_mutex_unlock (&self->state_lock);
78 
79       break;
80 
81     case PTHREAD_JOINABLE:
82       /* We need to stay around for a while since another thread
83          might want to join us.  */
84       self->state = PTHREAD_EXITED;
85 
86       /* We need to remember the exit status.  A thread joining us
87          might ask for it.  */
88       self->status = status;
89 
90       /* Broadcast the condition.  This will wake up threads that are
91          waiting to join us.  */
92       __pthread_cond_broadcast (&self->state_cond);
93       __pthread_mutex_unlock (&self->state_lock);
94 
95       break;
96     }
97 
98   /* Destroy any signal state.  */
99   __pthread_sigstate_destroy (self);
100 
101   /* Self terminating requires TLS, so defer the release of the TCB until
102      the thread structure is reused.  */
103 
104   /* Release kernel resources, including the kernel thread and the stack,
105      and drop the self reference.  */
106   __pthread_thread_terminate (self);
107 
108   /* NOTREACHED */
109   abort ();
110 }
111 
112 weak_alias (__pthread_exit, pthread_exit);
113