Fix guards for qecvt
[platform/upstream/glibc.git] / stdlib / cxa_atexit.c
1 /* Copyright (C) 1999-2013 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    <http://www.gnu.org/licenses/>.  */
17
18 #include <assert.h>
19 #include <stdlib.h>
20
21 #include <bits/libc-lock.h>
22 #include "exit.h"
23 #include <atomic.h>
24 #include <sysdep.h>
25
26 #undef __cxa_atexit
27
28
29 int
30 attribute_hidden
31 __internal_atexit (void (*func) (void *), void *arg, void *d,
32                    struct exit_function_list **listp)
33 {
34   struct exit_function *new = __new_exitfn (listp);
35
36   if (new == NULL)
37     return -1;
38
39 #ifdef PTR_MANGLE
40   PTR_MANGLE (func);
41 #endif
42   new->func.cxa.fn = (void (*) (void *, int)) func;
43   new->func.cxa.arg = arg;
44   new->func.cxa.dso_handle = d;
45   atomic_write_barrier ();
46   new->flavor = ef_cxa;
47   return 0;
48 }
49
50
51 /* Register a function to be called by exit or when a shared library
52    is unloaded.  This function is only called from code generated by
53    the C++ compiler.  */
54 int
55 __cxa_atexit (void (*func) (void *), void *arg, void *d)
56 {
57   return __internal_atexit (func, arg, d, &__exit_funcs);
58 }
59 INTDEF(__cxa_atexit)
60
61
62 /* We change global data, so we need locking.  */
63 __libc_lock_define_initialized (static, lock)
64
65
66 static struct exit_function_list initial;
67 struct exit_function_list *__exit_funcs = &initial;
68 uint64_t __new_exitfn_called;
69
70 struct exit_function *
71 __new_exitfn (struct exit_function_list **listp)
72 {
73   struct exit_function_list *p = NULL;
74   struct exit_function_list *l;
75   struct exit_function *r = NULL;
76   size_t i = 0;
77
78   __libc_lock_lock (lock);
79
80   for (l = *listp; l != NULL; p = l, l = l->next)
81     {
82       for (i = l->idx; i > 0; --i)
83         if (l->fns[i - 1].flavor != ef_free)
84           break;
85
86       if (i > 0)
87         break;
88
89       /* This block is completely unused.  */
90       l->idx = 0;
91     }
92
93   if (l == NULL || i == sizeof (l->fns) / sizeof (l->fns[0]))
94     {
95       /* The last entry in a block is used.  Use the first entry in
96          the previous block if it exists.  Otherwise create a new one.  */
97       if (p == NULL)
98         {
99           assert (l != NULL);
100           p = (struct exit_function_list *)
101             calloc (1, sizeof (struct exit_function_list));
102           if (p != NULL)
103             {
104               p->next = *listp;
105               *listp = p;
106             }
107         }
108
109       if (p != NULL)
110         {
111           r = &p->fns[0];
112           p->idx = 1;
113         }
114     }
115   else
116     {
117       /* There is more room in the block.  */
118       r = &l->fns[i];
119       l->idx = i + 1;
120     }
121
122   /* Mark entry as used, but we don't know the flavor now.  */
123   if (r != NULL)
124     {
125       r->flavor = ef_us;
126       ++__new_exitfn_called;
127     }
128
129   __libc_lock_unlock (lock);
130
131   return r;
132 }