~ubuntu-branches/ubuntu/trusty/libgii/trusty

« back to all changes in this revision

Viewing changes to gg/cleanup.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Albert
  • Date: 2001-08-27 23:17:32 UTC
  • Revision ID: james.westby@ubuntu.com-20010827231732-5kiieyxb3mvj25ur
Tags: upstream-0.8.1
ImportĀ upstreamĀ versionĀ 0.8.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: cleanup.c,v 1.1.1.1 2001/05/12 23:00:06 cegger Exp $
 
2
******************************************************************************
 
3
 
 
4
   LibGG - Functions for adding and removing cleanup callbacks
 
5
 
 
6
   Copyright (C) 1998 Marcus Sundberg   [marcus@ggi-project.org]
 
7
 
 
8
   Permission is hereby granted, free of charge, to any person obtaining a
 
9
   copy of this software and associated documentation files (the "Software"),
 
10
   to deal in the Software without restriction, including without limitation
 
11
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
12
   and/or sell copies of the Software, and to permit persons to whom the
 
13
   Software is furnished to do so, subject to the following conditions:
 
14
 
 
15
   The above copyright notice and this permission notice shall be included in
 
16
   all copies or substantial portions of the Software.
 
17
 
 
18
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
19
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
20
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
21
   THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 
22
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
23
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
24
 
 
25
******************************************************************************
 
26
*/
 
27
 
 
28
#include <stdlib.h>
 
29
#include <ggi/gg.h>
 
30
#include "plat.h"
 
31
 
 
32
#ifdef HAVE_UNISTD_H
 
33
#include <unistd.h>
 
34
#endif
 
35
#ifdef HAVE_SIGNAL_H
 
36
#include <signal.h>
 
37
#endif
 
38
 
 
39
typedef struct funclist {
 
40
        ggcleanup_func  *func;
 
41
        void            *arg;
 
42
        struct funclist *next;
 
43
} funclist;
 
44
 
 
45
static funclist *firstfunc = NULL;
 
46
static ggcleanup_func *currentfunc = NULL;
 
47
static int is_registered = 0;
 
48
static int force_exit = 0;
 
49
 
 
50
 
 
51
static void do_cleanup(void)
 
52
{
 
53
        funclist *curr = firstfunc, *prev;
 
54
        
 
55
        while (curr != NULL) {
 
56
                currentfunc = curr->func;
 
57
                curr->func(curr->arg);
 
58
                prev = curr;
 
59
                curr = curr->next;
 
60
                currentfunc = NULL;
 
61
                /* Make sure we don't call the function again */
 
62
                ggUnregisterCleanup(prev->func, prev->arg);
 
63
        }
 
64
}
 
65
 
 
66
static void cleanup_function(void)
 
67
{
 
68
        do_cleanup();
 
69
#ifdef HAVE__EXIT
 
70
        if (force_exit) {
 
71
                _exit(0);
 
72
        }
 
73
#endif
 
74
}
 
75
 
 
76
static void cleanup_function_ret(int retval)
 
77
{
 
78
        do_cleanup();
 
79
#ifdef HAVE__EXIT
 
80
        if (force_exit) {
 
81
                _exit(retval);
 
82
        }
 
83
#endif
 
84
}
 
85
 
 
86
 
 
87
 
 
88
#if defined(HAVE_SIGNAL) || defined(HAVE_SIGACTION)
 
89
 
 
90
typedef void (ggsighandler)(int);
 
91
 
 
92
typedef struct {
 
93
        int               sig;
 
94
        ggsighandler     *oldhandler;
 
95
#ifdef HAVE_SIGACTION
 
96
        struct sigaction  oldsa;
 
97
#endif
 
98
} gg_siginfo;
 
99
 
 
100
 
 
101
static gg_siginfo siglist[] = {
 
102
#ifdef SIGHUP
 
103
        { SIGHUP,  SIG_ERR },
 
104
#endif
 
105
#ifdef SIGINT
 
106
        { SIGINT,  SIG_ERR },
 
107
#endif
 
108
#ifdef SIGQUIT
 
109
        { SIGQUIT, SIG_ERR },
 
110
#endif
 
111
#ifdef SIGILL
 
112
        { SIGILL,  SIG_ERR },
 
113
#endif
 
114
#ifdef SIGTRAP
 
115
        { SIGTRAP, SIG_ERR },
 
116
#endif
 
117
#ifdef SIGABRT
 
118
        { SIGABRT, SIG_ERR },
 
119
#endif
 
120
#ifdef SIGBUS
 
121
        { SIGBUS,  SIG_ERR },
 
122
#endif
 
123
#ifdef SIGFPE
 
124
        { SIGFPE,  SIG_ERR },
 
125
#endif
 
126
#ifdef SIGSEGV
 
127
        { SIGSEGV, SIG_ERR },
 
128
#endif
 
129
#ifdef SIGPIPE
 
130
        { SIGPIPE, SIG_ERR },
 
131
#endif
 
132
#ifdef SIGALRM
 
133
        { SIGALRM, SIG_ERR },
 
134
#endif
 
135
#ifdef SIGTERM
 
136
        { SIGTERM, SIG_ERR },
 
137
#endif
 
138
#ifdef SIGSTKFLT
 
139
        { SIGSTKFLT, SIG_ERR },
 
140
#endif
 
141
#ifdef SIGIO
 
142
        { SIGIO,   SIG_ERR },
 
143
#endif
 
144
#if defined(SIGPOLL) && (SIGPOLL != SIGIO)
 
145
        { SIGPOLL, SIG_ERR },
 
146
#endif
 
147
#ifdef SIGXCPU
 
148
        { SIGXCPU, SIG_ERR },
 
149
#endif
 
150
#ifdef SIGXFSZ
 
151
        { SIGXFSZ, SIG_ERR },
 
152
#endif
 
153
#ifdef SIGVTALRM
 
154
        { SIGVTALRM, SIG_ERR },
 
155
#endif
 
156
#ifdef SIGPROF
 
157
        { SIGPROF, SIG_ERR },
 
158
#endif
 
159
#ifdef SIGPWR
 
160
        { SIGPWR,  SIG_ERR },
 
161
#endif
 
162
#ifdef SIGLOST
 
163
        { SIGLOST, SIG_ERR },
 
164
#endif
 
165
#ifdef SIGUNUSED
 
166
        { SIGUNUSED, SIG_ERR }
 
167
#endif
 
168
};
 
169
 
 
170
#define SIGLIST_LEN     sizeof(siglist)/sizeof(gg_siginfo)
 
171
 
 
172
 
 
173
static void sighandler(int signum)
 
174
{
 
175
        int i;
 
176
        ggsighandler *oldfunc = NULL;
 
177
 
 
178
        for (i = 0; i < SIGLIST_LEN; i++) {
 
179
                if (siglist[i].sig == signum) {
 
180
                        if (siglist[i].oldhandler == SIG_IGN) {
 
181
                                signal(signum, sighandler);
 
182
                                return;
 
183
                        }
 
184
                        if (siglist[i].oldhandler != SIG_DFL) {
 
185
                                oldfunc = siglist[i].oldhandler;
 
186
                                break;
 
187
                        }
 
188
                }
 
189
        }
 
190
        if (oldfunc) {
 
191
                oldfunc(signum);
 
192
        }
 
193
        fprintf(stderr, "Terminating on signal %d\n", signum);
 
194
        cleanup_function_ret(signum);
 
195
        exit(signum);
 
196
}
 
197
 
 
198
 
 
199
#ifdef HAVE_SIGACTION
 
200
 
 
201
static void setsa(struct sigaction *sa, ggsighandler *func)
 
202
{
 
203
        sa->sa_handler = func;
 
204
        sa->sa_flags = 0;
 
205
        sigemptyset(&sa->sa_mask);
 
206
}
 
207
 
 
208
static void unregister_sighandler(void)
 
209
{
 
210
        int i;
 
211
 
 
212
        for (i = 0; i < SIGLIST_LEN; i++) {
 
213
                struct sigaction sa;
 
214
 
 
215
                if (siglist[i].oldhandler == SIG_ERR) continue;
 
216
                if (sigaction(siglist[i].sig, NULL, &sa) != 0) continue;
 
217
                if (sa.sa_flags == 0 && sa.sa_handler == sighandler) {
 
218
                        sigaction(siglist[i].sig, &siglist[i].oldsa, NULL);
 
219
                } else {
 
220
                        /* Someone else has changed this signal action, so
 
221
                           we shouldn't touch it */
 
222
                }
 
223
 
 
224
                siglist[i].oldhandler = SIG_ERR;
 
225
        }
 
226
}               
 
227
 
 
228
static void register_sighandler(void)
 
229
{
 
230
        int i;
 
231
 
 
232
        for (i = 0; i < SIGLIST_LEN; i++) {
 
233
                if (sigaction(siglist[i].sig, NULL, &siglist[i].oldsa) != 0) {
 
234
                        continue;
 
235
                }
 
236
                if (siglist[i].oldsa.sa_handler == SIG_DFL ||
 
237
                    siglist[i].oldsa.sa_handler == SIG_IGN) {
 
238
                        struct sigaction sa;
 
239
 
 
240
                        setsa(&sa, sighandler);
 
241
                        if (sigaction(siglist[i].sig, &sa, NULL) != 0) {
 
242
                                continue;
 
243
                        }
 
244
                        siglist[i].oldhandler = siglist[i].oldsa.sa_handler;
 
245
                }
 
246
        }
 
247
}
 
248
 
 
249
#else /* HAVE_SIGACTION */
 
250
 
 
251
static void unregister_sighandler(void)
 
252
{
 
253
        int i;
 
254
 
 
255
        for (i = 0; i < SIGLIST_LEN; i++) {
 
256
                ggsighandler *oldfunc;
 
257
 
 
258
                if (siglist[i].oldhandler == SIG_ERR) continue;
 
259
                oldfunc = signal(siglist[i].sig, siglist[i].oldhandler);
 
260
                if (oldfunc != sighandler) {
 
261
                        /* Someone else has changed this signal handler, so
 
262
                           we shouldn't touch it */
 
263
                        signal(siglist[i].sig, oldfunc);
 
264
                }
 
265
                siglist[i].oldhandler = SIG_ERR;
 
266
        }
 
267
}               
 
268
 
 
269
static void register_sighandler(void)
 
270
{
 
271
        int i;
 
272
 
 
273
        for (i = 0; i < SIGLIST_LEN; i++) {
 
274
                ggsighandler *oldfunc;
 
275
 
 
276
                oldfunc = signal(siglist[i].sig, sighandler);
 
277
                if (oldfunc != SIG_DFL &&
 
278
                    oldfunc != SIG_IGN) {
 
279
                        /* If there's a sighandler registered already we don't
 
280
                           have to care */
 
281
                        if (oldfunc != SIG_ERR) {
 
282
                                signal(siglist[i].sig, oldfunc);
 
283
                        }
 
284
                        continue;
 
285
                }
 
286
                siglist[i].oldhandler = oldfunc;
 
287
        }
 
288
}
 
289
#endif /* HAVE_SIGACTION */
 
290
 
 
291
#else /* HAVE_SIGNAL || HAVE_SIGACTION */
 
292
 
 
293
#define register_sighandler() /* empty */
 
294
#define unregister_sighandler() /* empty */
 
295
 
 
296
#endif /* HAVE_SIGNAL || HAVE_SIGACTION */                      
 
297
 
 
298
int ggRegisterCleanup(ggcleanup_func *func, void *arg)
 
299
{
 
300
        int ret = 0;
 
301
        funclist *newlist;
 
302
 
 
303
        ggLock(_gg_global_mutex);
 
304
        register_sighandler();
 
305
        if (!is_registered) {
 
306
                if (atexit(cleanup_function) != 0) {
 
307
                        ret = GGI_EUNKNOWN;
 
308
                        goto out;
 
309
                }
 
310
                is_registered = 1;
 
311
        }
 
312
        if ((newlist = malloc(sizeof(funclist))) == NULL) {
 
313
                ret = GGI_ENOMEM;
 
314
                goto out;
 
315
        }
 
316
        newlist->func = func;
 
317
        newlist->arg = arg;
 
318
        
 
319
        /* Insert first in list */
 
320
        newlist->next = firstfunc;
 
321
        firstfunc = newlist;
 
322
 
 
323
  out:
 
324
        ggUnlock(_gg_global_mutex);
 
325
 
 
326
        return ret;
 
327
}
 
328
 
 
329
 
 
330
int ggUnregisterCleanup(ggcleanup_func *func, void *arg)
 
331
{
 
332
        funclist *curr = firstfunc, *prev = NULL;
 
333
 
 
334
        if (func == currentfunc) {
 
335
                /* Don't unregister a function while it is being called */
 
336
                return 0;
 
337
        }
 
338
        ggLock(_gg_global_mutex);
 
339
        while (curr != NULL) {
 
340
                if (curr->func == func && curr->arg == arg) {
 
341
                        if (curr == firstfunc) firstfunc = curr->next;
 
342
                        else prev->next = curr->next;
 
343
                        free(curr);
 
344
                        if (firstfunc == NULL) unregister_sighandler();
 
345
                        ggUnlock(_gg_global_mutex);
 
346
                        return 0;
 
347
                }
 
348
                prev = curr;
 
349
                curr = curr->next;
 
350
        }
 
351
 
 
352
        ggUnlock(_gg_global_mutex);
 
353
        return GGI_ENOTALLOC;
 
354
}
 
355
 
 
356
 
 
357
void ggCleanupForceExit(void)
 
358
{
 
359
        force_exit = 1;
 
360
}