Remove 'grp' and merge into 'nss' and 'posix'
[platform/upstream/glibc.git] / stdlib / exit.c
1 /* Copyright (C) 1991-2023 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <pointer_guard.h>
22 #include <libc-lock.h>
23 #include <set-freeres.h>
24 #include "exit.h"
25
26 /* Initialize the flag that indicates exit function processing
27    is complete. See concurrency notes in stdlib/exit.h where
28    __exit_funcs_lock is declared.  */
29 bool __exit_funcs_done = false;
30
31 /* Call all functions registered with `atexit' and `on_exit',
32    in the reverse of the order in which they were registered
33    perform stdio cleanup, and terminate program execution with STATUS.  */
34 void
35 attribute_hidden
36 __run_exit_handlers (int status, struct exit_function_list **listp,
37                      bool run_list_atexit, bool run_dtors)
38 {
39   /* First, call the TLS destructors.  */
40   if (run_dtors)
41     call_function_static_weak (__call_tls_dtors);
42
43   __libc_lock_lock (__exit_funcs_lock);
44
45   /* We do it this way to handle recursive calls to exit () made by
46      the functions registered with `atexit' and `on_exit'. We call
47      everyone on the list and use the status value in the last
48      exit (). */
49   while (true)
50     {
51       struct exit_function_list *cur;
52
53     restart:
54       cur = *listp;
55
56       if (cur == NULL)
57         {
58           /* Exit processing complete.  We will not allow any more
59              atexit/on_exit registrations.  */
60           __exit_funcs_done = true;
61           break;
62         }
63
64       while (cur->idx > 0)
65         {
66           struct exit_function *const f = &cur->fns[--cur->idx];
67           const uint64_t new_exitfn_called = __new_exitfn_called;
68
69           switch (f->flavor)
70             {
71               void (*atfct) (void);
72               void (*onfct) (int status, void *arg);
73               void (*cxafct) (void *arg, int status);
74               void *arg;
75
76             case ef_free:
77             case ef_us:
78               break;
79             case ef_on:
80               onfct = f->func.on.fn;
81               arg = f->func.on.arg;
82               PTR_DEMANGLE (onfct);
83
84               /* Unlock the list while we call a foreign function.  */
85               __libc_lock_unlock (__exit_funcs_lock);
86               onfct (status, arg);
87               __libc_lock_lock (__exit_funcs_lock);
88               break;
89             case ef_at:
90               atfct = f->func.at;
91               PTR_DEMANGLE (atfct);
92
93               /* Unlock the list while we call a foreign function.  */
94               __libc_lock_unlock (__exit_funcs_lock);
95               atfct ();
96               __libc_lock_lock (__exit_funcs_lock);
97               break;
98             case ef_cxa:
99               /* To avoid dlclose/exit race calling cxafct twice (BZ 22180),
100                  we must mark this function as ef_free.  */
101               f->flavor = ef_free;
102               cxafct = f->func.cxa.fn;
103               arg = f->func.cxa.arg;
104               PTR_DEMANGLE (cxafct);
105
106               /* Unlock the list while we call a foreign function.  */
107               __libc_lock_unlock (__exit_funcs_lock);
108               cxafct (arg, status);
109               __libc_lock_lock (__exit_funcs_lock);
110               break;
111             }
112
113           if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
114             /* The last exit function, or another thread, has registered
115                more exit functions.  Start the loop over.  */
116             goto restart;
117         }
118
119       *listp = cur->next;
120       if (*listp != NULL)
121         /* Don't free the last element in the chain, this is the statically
122            allocate element.  */
123         free (cur);
124     }
125
126   __libc_lock_unlock (__exit_funcs_lock);
127
128   if (run_list_atexit)
129     call_function_static_weak (_IO_cleanup);
130
131   _exit (status);
132 }
133
134
135 void
136 exit (int status)
137 {
138   __run_exit_handlers (status, &__exit_funcs, true, true);
139 }
140 libc_hidden_def (exit)