1ggRegisterCleanup(3) GGI ggRegisterCleanup(3)
2
3
4
6 ggRegisterCleanup, ggUnregisterCleanup, ggCleanupForceExit : Cleanup
7 callback facilities
8
10 #include <ggi/gg.h>
11
12 typedef void (ggcleanup_func)(void *);
13
14 int ggRegisterCleanup(ggcleanup_func *func, void *arg);
15
16 int ggUnregisterCleanup(ggcleanup_func *func, void *arg);
17
18 void ggCleanupForceExit(void);
19
20
22 ggRegisterCleanup registers a callback function ("handler") to be exe‐
23 cuted when any abnormal or unexpected program termination is imminent.
24 The function will be called with its argument.
25
26 ggUnregisterCleanup cancels a callback installed with ggRegister‐
27 Cleanup. If more than one exactly identical callbacks have been
28 installed, the most recently installed one is canceled.
29
30 ggCleanupForceExit may only be called from within a LibGG cleanup han‐
31 dler. Once ggCleanupForceExit is called, _exit(2) will be explicitly
32 called after all registered cleanup callbacks have completed by
33 ggExit(3), assuming there is no error that prevents them from complet‐
34 ing. It is not possible to cancel such a request once it has been
35 made.
36
37 Cleanup functions are executed in LIFO order. They are guaranteed to
38 only be executed once during program termination or during ggExit(3).
39
40 These functions are for emergency use only, and should not be used as a
41 substitute to proper memory deallocation routines. They should only be
42 used to restore system state that would otherwise be left corrupted
43 after an abnormal program termination, for example, a video-card timing
44 mode or tty mode. When normal termination occurs, ggUnregisterCleanup
45 should be called to systematically remove the emergency callbacks
46 before ggExit(3) or exit(3) are called.
47
48 Callback functions registered with ggRegisterCleanup should not them‐
49 selves invoke (or invoke any subroutines that may in turn invoke) any
50 of the LibGG locking functions ggLockCreate(3), ggLockDestroy(3),
51 ggLock(3), ggUnlock(3), or ggTryLock(3). However, since callbacks are
52 only invoked during emergencies, they should be ignoring locks in gen‐
53 eral. If a callback function may be used by anything other than LibGG,
54 it must also be reentrant. Callback functions can come at any time, so
55 write them with this in mind -- make them minimal and tolerant of con‐
56 current access to global read/write data and avoid accessing such data
57 in the first place if it is not absolutely necessary.
58
59 The callback functions may be called by a normal call to ggExit(3). As
60 such, it is considered best practice to use ggUnregisterCleanup to
61 remove cleanups when gracefully deinitializing LibGG or a library that
62 uses LibGG, before ggExit(3) is called.
63
64 ggRegisterCleanup and ggUnregisterCleanup are threadsafe, however, they
65 are not safe to call from a thread that may be canceled during their
66 execution, and they are not guaranteed to be safe to call from LibGG
67 tasks or any other special context such as a signal handler or a asyn‐
68 cronous procedure call. Above all they should not be called from
69 inside a LibGG cleanup handler.
70
72 ggRegisterCleanup returns GGI_OK on success, or one of these error
73 codes:
74
75 · GGI_EUNKNOWN;
76
77 · GGI_ENOMEM;
78
79 · GGI_EBUSY.
80
81 ggUnregisterCleanup returns GGI_OK on success, or one of these error
82 codes:
83
84 · GGI_EBUSY;
85
86 · GGI_ENOTALLOC;
87
88 · GGI_ENOMEM.
89
91 On UNIX systems the LibGG cleanup facilities install signal handlers as
92 per signal(3) or sigaction(2). It is advisible to use LibGG cleanup
93 handlers instead of UNIX signals for the purpose of catching fatal sig‐
94 nals because they are implemented portably, however, this is not always
95 an option when mixing LibGG with other libraries. When LibGG must be
96 used with other code that also installs signal handlers, consult the
97 following section.
98
99 LibGG installs signal handlers for those signals which are normally
100 fatal to the program. The exact set of functions that is caught
101 depends on the software platform. LibGG installs signal handlers when
102 the first LibGG cleanup handler is installed. These may in fact be
103 installed in ggInit(3) as LibGG may use cleanups internally. The only
104 way to be sure that the LibGG signal handlers are installed is to
105 install a cleanup after ggInit(3).
106
107 By setting any signal handler to SIG_IGN before calling ggInit(3), the
108 application can force LibGG to ignore the signal, so that cleanups are
109 not run when that particular signal is received. LibGG will also over‐
110 load any application signal handlers for fatal signals that are present
111 when it installs a signal handler. Overloaded signal handlers will be
112 run before cleanups are run when the signal occurs. The overloaded
113 signal handler is not guaranteed to be called exactly as it would be by
114 the main application, for example, support for the long form of the
115 signal handler prototype available through sigaction(2) on some systems
116 is not yet implemented, though it may be in the future.
117
118 If the system uses the tradition (broken) UNIX signal behavior where
119 signal handlers are set to SIG_DFL to 'block' additional occurances,
120 this may result in rare instances where signal handlers are reentered.
121 Thus the signal handler for a given signal may call the overloaded
122 cleanup multiple times before cleanup functions are called. This will
123 also apply to signal handlers that manipulate the signal mask on more
124 advanced sigaction(2) based systems.
125
126 Signals that arrive after that signal which triggers the cleanup call‐
127 backs may have their handlers run before or during the execution of the
128 cleanups.
129
130 After ggInit(3) and ggRegisterCleanup are called, individual signals
131 may be overridden by application-specific signal handlers or set to
132 SIG_IGN or SIG_DFL. This will prevent LibGG cleanups from being run
133 when the signal occurs. Within limits, it is also acceptable to over‐
134 load the LibGG signal handler. However it is not acceptable to call
135 the LibGG signal handler with signum equal to any signal on which LibGG
136 did not initially install the handler function, and deinitializing
137 LibGG while overloading its signal handler may cause undefined bahav‐
138 ior.
139
141 LibGG attempts to be tolerant of badly written signal handlers, but
142 consistant, correct behavior can only be guaranteed if signal handlers
143 are written within the following guidelines. First, a signal handler
144 must be written using sigaction if sigaction is available, or the
145 results may not be perfect. If sigaction is not available, the proper
146 code for a simple, overloadable signal handler is such:
147
148 lasthandler = signal(signum, SIG_DFL));
149 /* do stuff */
150 if (lasthandler == SIG_DFL) signal(signum, current_handler);
151 else signal(signum, lasthandler);
152
153 This code looks circumlocuitous but each part is important for main‐
154 taining overloadability in a portable fashion. The signal handler
155 should not reinstall itself unless it detects original UNIX signals are
156 in effect by detecting the automatically installed SIG_DFL, or else it
157 might get called directly, skipping the parent signal handler.
158 Installing SIG_DFL temporarily should be harmless to BSD style signals
159 because the OS is required to block stacked signals through some other
160 mechanism until the signal handler returns.
161
162 In order to overload a signal handler, again still dealing with the
163 situation where sigaction is not available, the above code can be modi‐
164 fied as such:
165
166 lasthandler = signal(signum, SIG_DFL);
167 /* do stuff */
168 if (had_oldhandler) {
169 signal(signum, lasthandler);
170 oldhandler(signum);
171 }
172 if (lasthandler == SIG_DFL) signal(signum, current_handler);
173 else signal(signum, lasthandler);
174
175 This is not perfect because it may allow lasthandler to be reentered
176 when used on a system with the original UNIX behavior, in the short
177 period between when lasthandler is reinstalled and the oldhandler
178 installs SIG_DFL. However, if the handlers are all reentrant this
179 should work fine. In the BSD behavior, this again is harmless because
180 other OS mechanisms prevent reentry.
181
182 Systems without sigaction are pretty cretinous and rarer these days,
183 however. When sigaction(2) is available we can assume that signal han‐
184 dlers do not need to reinstall themselves as per the original UNIX
185 SIG_DFL behavior. As such no special consideration is needed to write
186 a proper overloading/overloadable handler, however, in order to assure
187 that cleanup functions are only run once even in multithreaded, multi‐
188 processor environments, LibGG may need to temporarily overload a signal
189 handler which has overloaded LibGG's signal handler with a dummy pass-
190 through handler, and as of this writing LibGG's behavior when the sig‐
191 nal mask is altered is not yet specified and should be considered unde‐
192 fined.
193
194 Measures are taken within LibGG to limit the impact of interaction with
195 badly written signal handlers that reinstall their own handler when it
196 is not needed or desired, however it is recommended that libraries that
197 use such handlers be updated to use better code when compiled on more
198 modern systems.
199
200 One last note on stacking signal handlers: When writing for an environ‐
201 ment where different libraries may overload signals, all libraries must
202 prevent loops from forming. It is not sufficient that they simply
203 check that they never overload their own signal handler, because
204 another library may have overloaded it already, and thus you may have
205 handler A calling handler B calling handler A which then calls handler
206 B again. Libraries must keep track of whether their signal handlers
207 are installed or not through other means.
208
210 LibGG expects some sort of signal-like system to be present in the
211 environment, otherwise there is no way to implement the behavior
212 described above. When LibGG is compiled on a system that has no such
213 support, a fallback mode is invoked where cleanup handlers are regis‐
214 tered with the atexit(3) facility, or anything it may have that is like
215 atexit(3). It may not be possible to unregister cleanups supported in
216 such a way, and they will always run at normal program exit, even after
217 LibGG is exited. There is no way for them to run during abnormal ter‐
218 mination.
219
220
221
222libgg-1.0.x 2005-08-26 ggRegisterCleanup(3)