~xnox/ubuntu/trusty/gcc-arm-linux-androideabi/dima

« back to all changes in this revision

Viewing changes to android/bionic/libc/stdlib/atexit.c

  • Committer: Package Import Robot
  • Author(s): Dmitrijs Ledkovs
  • Date: 2013-07-05 10:12:24 UTC
  • Revision ID: package-import@ubuntu.com-20130705101224-6qo3e8jbz8p31aa1
Tags: upstream-0.20130705.1
ImportĀ upstreamĀ versionĀ 0.20130705.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $OpenBSD: atexit.c,v 1.14 2007/09/05 20:47:47 chl Exp $ */
 
2
/*
 
3
 * Copyright (c) 2002 Daniel Hartmeier
 
4
 * All rights reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions
 
8
 * are met:
 
9
 *
 
10
 *    - Redistributions of source code must retain the above copyright
 
11
 *      notice, this list of conditions and the following disclaimer.
 
12
 *    - Redistributions in binary form must reproduce the above
 
13
 *      copyright notice, this list of conditions and the following
 
14
 *      disclaimer in the documentation and/or other materials provided
 
15
 *      with the distribution.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
18
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
19
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 
20
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 
21
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 
22
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 
23
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
24
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 
25
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 
27
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
28
 * POSSIBILITY OF SUCH DAMAGE.
 
29
 *
 
30
 */
 
31
 
 
32
#include <sys/types.h>
 
33
#include <sys/mman.h>
 
34
#include <stdlib.h>
 
35
#include <string.h>
 
36
#include <unistd.h>
 
37
#include "atexit.h"
 
38
#include "thread_private.h"
 
39
 
 
40
int __atexit_invalid = 1;
 
41
struct atexit *__atexit;
 
42
 
 
43
/*
 
44
 * Function pointers are stored in a linked list of pages. The list
 
45
 * is initially empty, and pages are allocated on demand. The first
 
46
 * function pointer in the first allocated page (the last one in
 
47
 * the linked list) is reserved for the cleanup function.
 
48
 *
 
49
 * Outside the following functions, all pages are mprotect()'ed
 
50
 * to prevent unintentional/malicious corruption.
 
51
 */
 
52
 
 
53
/*
 
54
 * Register a function to be performed at exit or when a shared object
 
55
 * with the given dso handle is unloaded dynamically.  Also used as
 
56
 * the backend for atexit().  For more info on this API, see:
 
57
 *
 
58
 *      http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor
 
59
 */
 
60
int
 
61
__cxa_atexit(void (*func)(void *), void *arg, void *dso)
 
62
{
 
63
        struct atexit *p = __atexit;
 
64
        struct atexit_fn *fnp;
 
65
        int pgsize = getpagesize();
 
66
        int ret = -1;
 
67
 
 
68
        if (pgsize < (int)sizeof(*p))
 
69
                return (-1);
 
70
        _ATEXIT_LOCK();
 
71
        p = __atexit;
 
72
        if (p != NULL) {
 
73
                if (p->ind + 1 >= p->max)
 
74
                        p = NULL;
 
75
                else if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
 
76
                        goto unlock;
 
77
        }
 
78
        if (p == NULL) {
 
79
                p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
 
80
                    MAP_ANON | MAP_PRIVATE, -1, 0);
 
81
                if (p == MAP_FAILED)
 
82
                        goto unlock;
 
83
                if (__atexit == NULL) {
 
84
                        memset(&p->fns[0], 0, sizeof(p->fns[0]));
 
85
                        p->ind = 1;
 
86
                } else
 
87
                        p->ind = 0;
 
88
                p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
 
89
                    sizeof(p->fns[0]);
 
90
                p->next = __atexit;
 
91
                __atexit = p;
 
92
                if (__atexit_invalid)
 
93
                        __atexit_invalid = 0;
 
94
        }
 
95
        fnp = &p->fns[p->ind++];
 
96
        fnp->fn_ptr.cxa_func = func;
 
97
        fnp->fn_arg = arg;
 
98
        fnp->fn_dso = dso;
 
99
        if (mprotect(p, pgsize, PROT_READ))
 
100
                goto unlock;
 
101
        ret = 0;
 
102
unlock:
 
103
        _ATEXIT_UNLOCK();
 
104
        return (ret);
 
105
}
 
106
 
 
107
#ifdef CRT_LEGACY_WORKAROUND
 
108
/*
 
109
 * Register a function to be performed at exit.
 
110
 */
 
111
int
 
112
atexit(void (*func)(void))
 
113
{
 
114
        return (__cxa_atexit((void (*)(void *))func, NULL, NULL));
 
115
}
 
116
#endif
 
117
 
 
118
/*
 
119
 * Call all handlers registered with __cxa_atexit() for the shared
 
120
 * object owning 'dso'.
 
121
 * Note: if 'dso' is NULL, then all remaining handlers are called.
 
122
 */
 
123
void
 
124
__cxa_finalize(void *dso)
 
125
{
 
126
        struct atexit *p, *q;
 
127
        struct atexit_fn fn;
 
128
        int n, pgsize = getpagesize();
 
129
        static int call_depth;
 
130
 
 
131
        if (__atexit_invalid)
 
132
                return;
 
133
 
 
134
        call_depth++;
 
135
 
 
136
        for (p = __atexit; p != NULL; p = p->next) {
 
137
                for (n = p->ind; --n >= 0;) {
 
138
                        if (p->fns[n].fn_ptr.cxa_func == NULL)
 
139
                                continue;       /* already called */
 
140
                        if (dso != NULL && dso != p->fns[n].fn_dso)
 
141
                                continue;       /* wrong DSO */
 
142
 
 
143
                        /*
 
144
                         * Mark handler as having been already called to avoid
 
145
                         * dupes and loops, then call the appropriate function.
 
146
                         */
 
147
                        fn = p->fns[n];
 
148
                        if (mprotect(p, pgsize, PROT_READ | PROT_WRITE) == 0) {
 
149
                                p->fns[n].fn_ptr.cxa_func = NULL;
 
150
                                mprotect(p, pgsize, PROT_READ);
 
151
                        }
 
152
#if ANDROID
 
153
                        /* it looks like we should always call the function
 
154
                         * with an argument, even if dso is not NULL. Otherwise
 
155
                         * static destructors will not be called properly on
 
156
                         * the ARM.
 
157
                         */
 
158
                        (*fn.fn_ptr.cxa_func)(fn.fn_arg);
 
159
#else /* !ANDROID */
 
160
                        if (dso != NULL)
 
161
                                (*fn.fn_ptr.cxa_func)(fn.fn_arg);
 
162
                        else
 
163
                                (*fn.fn_ptr.std_func)();
 
164
#endif /* !ANDROID */
 
165
                }
 
166
        }
 
167
 
 
168
        /*
 
169
         * If called via exit(), unmap the pages since we have now run
 
170
         * all the handlers.  We defer this until calldepth == 0 so that
 
171
         * we don't unmap things prematurely if called recursively.
 
172
         */
 
173
        if (dso == NULL && --call_depth == 0) {
 
174
                for (p = __atexit; p != NULL; ) {
 
175
                        q = p;
 
176
                        p = p->next;
 
177
                        munmap(q, pgsize);
 
178
                }
 
179
                __atexit = NULL;
 
180
        }
 
181
}
 
182
 
 
183
/*
 
184
 * Register the cleanup function
 
185
 */
 
186
void
 
187
__atexit_register_cleanup(void (*func)(void))
 
188
{
 
189
        struct atexit *p;
 
190
        int pgsize = getpagesize();
 
191
 
 
192
        if (pgsize < (int)sizeof(*p))
 
193
                return;
 
194
        _ATEXIT_LOCK();
 
195
        p = __atexit;
 
196
        while (p != NULL && p->next != NULL)
 
197
                p = p->next;
 
198
        if (p == NULL) {
 
199
                p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
 
200
                    MAP_ANON | MAP_PRIVATE, -1, 0);
 
201
                if (p == MAP_FAILED)
 
202
                        goto unlock;
 
203
                p->ind = 1;
 
204
                p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) /
 
205
                    sizeof(p->fns[0]);
 
206
                p->next = NULL;
 
207
                __atexit = p;
 
208
                if (__atexit_invalid)
 
209
                        __atexit_invalid = 0;
 
210
        } else {
 
211
                if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
 
212
                        goto unlock;
 
213
        }
 
214
        p->fns[0].fn_ptr.std_func = func;
 
215
        p->fns[0].fn_arg = NULL;
 
216
        p->fns[0].fn_dso = NULL;
 
217
        mprotect(p, pgsize, PROT_READ);
 
218
unlock:
 
219
        _ATEXIT_UNLOCK();
 
220
}