1 krisbash 1.1 #include "palcommon.h"
2
3 #if defined(USE_PAL_ATEXIT)
4 # include <stdlib.h>
5 # include <common.h>
6 # include <pthread.h>
7
8 typedef void (*AtexitFunc)();
9
10 /* Array of at-exit functions */
11 static AtexitFunc _funcs[PAL_ATEXIT_MAX];
12 static size_t _nfuncs;
13
14 /* Lock to synchronize access to _funcs and _nfuncs */
15
16 static pthread_mutex_t _lock = PTHREAD_MUTEX_INITIALIZER;
17
18 /* Used to detect re-entrancy errors */
19 static int _nesting;
20 static pthread_mutex_t _nestingLock = PTHREAD_MUTEX_INITIALIZER;
21
22 krisbash 1.1 /* Non-zero once the system atexit() has been called */
23 static int _initialized;
24
25 static void _AtForkPrepare()
26 {
27 /* Lock */
28 pthread_mutex_lock(&_lock);
29 pthread_mutex_lock(&_nestingLock);
30 }
31
32 static void _AtForkParent()
33 {
34 /* Unlock */
35 pthread_mutex_unlock(&_lock);
36 pthread_mutex_unlock(&_nestingLock);
37 }
38
39 static void _AtForkChild()
40 {
41 _initialized = 0;
42 /* Unlock */
43 krisbash 1.1 pthread_mutex_unlock(&_lock);
44 pthread_mutex_unlock(&_nestingLock);
45 }
46
47 static void _atexitFunc()
48 {
49 PAL_AtexitCall();
50 }
51
52 int PAL_Atexit(void (*func)())
53 {
54 /* Disallow if currently executing PAL_AtexitCall() */
55 pthread_mutex_lock(&_nestingLock);
56 {
57 DEBUG_ASSERT(_nesting == 0);
58
59 if (_nesting)
60 {
61 pthread_mutex_unlock(&_nestingLock);
62 return -1;
63 }
64 krisbash 1.1 }
65 pthread_mutex_unlock(&_nestingLock);
66
67 /* Install _atexitFunc() to be called on the first call */
68 if (_initialized == 0)
69 {
70 pthread_mutex_lock(&_lock);
71 {
72 if (_initialized == 0)
73 {
74 if (atexit(_atexitFunc) != 0)
75 {
76 pthread_mutex_unlock(&_lock);
77 return -1;
78 }
79
80 pthread_atfork(_AtForkPrepare, _AtForkParent, _AtForkChild);
81 _initialized = 1;
82 }
83 }
84 pthread_mutex_unlock(&_lock);
85 krisbash 1.1 }
86
87 /* Add the function to the array of functions */
88 pthread_mutex_lock(&_lock);
89 {
90 if (_nfuncs == PAL_ATEXIT_MAX)
91 {
92 pthread_mutex_unlock(&_lock);
93 return -1;
94 }
95
96 _funcs[_nfuncs++] = func;
97 }
98 pthread_mutex_unlock(&_lock);
99
100 return 0;
101 }
102
103 int PAL_AtexitCall()
104 {
105 /* Disallow if currently executing PAL_AtexitCall() */
106 krisbash 1.1 pthread_mutex_lock(&_nestingLock);
107 {
108 DEBUG_ASSERT(_nesting == 0);
109
110 if (_nesting)
111 {
112 pthread_mutex_unlock(&_nestingLock);
113 return -1;
114 }
115
116 _nesting = 1;
117 }
118 pthread_mutex_unlock(&_nestingLock);
119
120 /* Call all the functions and reset array to zero-size */
121 pthread_mutex_lock(&_lock);
122 {
123 size_t i;
124
125 for (i = 0; i < _nfuncs; i++)
126 (*_funcs[i])();
127 krisbash 1.1
128 _nfuncs = 0;
129 }
130 pthread_mutex_unlock(&_lock);
131
132 /* Reset _nesting to zero */
133 pthread_mutex_lock(&_nestingLock);
134 {
135 _nesting = 0;
136 }
137 pthread_mutex_unlock(&_nestingLock);
138
139 return 0;
140 }
141
142 #endif /* defined(USE_PAL_ATEXIT) */
|