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