]>
Commit | Line | Data |
---|---|---|
818ab71a | 1 | /* Copyright (C) 1999-2016 Free Software Foundation, Inc. |
99113dff DE |
2 | |
3 | NOTE: This source is derived from an old version taken from the GNU C | |
4 | Library (glibc). | |
5 | ||
6 | This file is part of GCC. | |
7 | ||
8 | GCC is free software; you can redistribute it and/or modify it under | |
9 | the terms of the GNU General Public License as published by the Free | |
10 | Software Foundation; either version 3, or (at your option) any later | |
11 | version. | |
12 | ||
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
17 | ||
18 | Under Section 7 of GPL version 3, you are granted additional | |
19 | permissions described in the GCC Runtime Library Exception, version | |
20 | 3.1, as published by the Free Software Foundation. | |
21 | ||
22 | You should have received a copy of the GNU General Public License and | |
23 | a copy of the GCC Runtime Library Exception along with this program; | |
24 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
25 | <http://www.gnu.org/licenses/>. */ | |
26 | ||
27 | #include <assert.h> | |
28 | #include <stdlib.h> | |
29 | #include "exit.h" | |
30 | ||
31 | ||
32 | static boolean_t | |
33 | catomic_compare_and_exchange_bool_acq (long *mem, long newval, long oldval) | |
34 | { | |
3dee689d DE |
35 | return ! __atomic_compare_exchange (mem, &oldval, &newval, 0, |
36 | __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); | |
99113dff DE |
37 | } |
38 | ||
39 | /* If D is non-NULL, call all functions registered with `__cxa_atexit' | |
40 | with the same dso handle. Otherwise, if D is NULL, call all of the | |
41 | registered handlers. */ | |
42 | void | |
43 | __cxa_finalize (void *d) | |
44 | { | |
45 | struct exit_function_list *funcs; | |
46 | ||
47 | restart: | |
48 | for (funcs = __exit_funcs; funcs; funcs = funcs->next) | |
49 | { | |
50 | struct exit_function *f; | |
51 | ||
52 | for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f) | |
53 | { | |
54 | void (*cxafn) (void *arg, int status); | |
55 | void *cxaarg; | |
56 | ||
57 | if ((d == NULL || d == f->func.cxa.dso_handle) | |
58 | /* We don't want to run this cleanup more than once. */ | |
59 | && (cxafn = f->func.cxa.fn, | |
60 | cxaarg = f->func.cxa.arg, | |
61 | ! catomic_compare_and_exchange_bool_acq (&f->flavor, ef_free, | |
62 | ef_cxa))) | |
63 | { | |
64 | uint64_t check = __new_exitfn_called; | |
65 | ||
66 | #ifdef PTR_DEMANGLE | |
67 | PTR_DEMANGLE (cxafn); | |
68 | #endif | |
69 | cxafn (cxaarg, 0); | |
70 | ||
71 | /* It is possible that that last exit function registered | |
72 | more exit functions. Start the loop over. */ | |
73 | if (__builtin_expect (check != __new_exitfn_called, 0)) | |
74 | goto restart; | |
75 | } | |
76 | } | |
77 | } | |
78 | ||
79 | /* Remove the registered fork handlers. We do not have to | |
80 | unregister anything if the program is going to terminate anyway. */ | |
81 | #ifdef UNREGISTER_ATFORK | |
82 | if (d != NULL) | |
83 | UNREGISTER_ATFORK (d); | |
84 | #endif | |
85 | } |