1 /*
2 * This file is part of the XForms library package.
3 *
4 * XForms is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1, or
7 * (at your option) any later version.
8 *
9 * XForms is distributed in the hope that it will be useful, but
10 * 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 License
15 * along with XForms. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /**
19 * \file signal.c
20 *
21 * This file is part of the XForms library package.
22 * Copyright (c) 1996-2002 T.C. Zhao
23 * All rights reserved.
24 *
25 * Simple minded quick&dirty signal handling.
26 *
27 * Only permit a specific signal to have one handler
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include "include/forms.h"
35 #include "flinternal.h"
36 #include <stdlib.h>
37 #include <signal.h>
38
39
40 void ( * fli_handle_signal )( void ) = NULL; /* also needed in handling.c */
41
42
43 /***************************************
44 ***************************************/
45
46 static void
handle_signal(void)47 handle_signal( void )
48 {
49 FLI_SIGNAL_REC *rec = fli_context->signal_rec;
50
51 for ( ; rec; rec = rec->next )
52 while ( rec->caught )
53 {
54 rec->caught--;
55 rec->callback( rec->signum, rec->data );
56 }
57 }
58
59
60 #ifndef FL_WIN32
61 #define IsDangerous( s ) ( ( s ) == SIGBUS \
62 || ( s ) == SIGSEGV \
63 || ( s ) == SIGILL \
64 || ( s ) == SIGFPE )
65 #else
66 #define IsDangerous( s ) 0
67 #endif
68
69 static int sig_direct;
70
71
72 /***************************************
73 ***************************************/
74
75 static RETSIGTYPE
default_signal_handler(int sig)76 default_signal_handler( int sig )
77 {
78 fl_signal_caught( sig );
79
80 /* if the signal is one of those that can cause infinite loops, handle it
81 and then exit */
82
83 if ( IsDangerous( sig ) )
84 {
85 handle_signal( );
86 fprintf( stderr, "Can't continue upon receiving signal %d\n", sig );
87 exit( sig );
88 }
89
90 #ifndef RETSIGTYPE_IS_VOID
91 return 0;
92 #endif
93 }
94
95
96 /***************************************
97 ***************************************/
98
99 void
fl_add_signal_callback(int s,FL_SIGNAL_HANDLER cb,void * data)100 fl_add_signal_callback( int s,
101 FL_SIGNAL_HANDLER cb,
102 void * data )
103 {
104 FLI_SIGNAL_REC *sig_rec,
105 *rec = fli_context->signal_rec;
106
107 if ( ! fli_handle_signal )
108 fli_handle_signal = handle_signal;
109
110 while ( rec && rec->signum != s )
111 rec = rec->next;
112
113 if ( rec )
114 {
115 rec->callback = cb;
116 rec->data = data;
117 }
118 else
119 {
120 sig_rec = fl_malloc( sizeof *sig_rec );
121 sig_rec->next = NULL;
122 sig_rec->data = data;
123 sig_rec->callback = cb;
124 sig_rec->signum = s;
125 sig_rec->caught = 0;
126
127 if ( ! sig_direct )
128 {
129 #if defined HAVE_SIGACTION
130 struct sigaction sact;
131
132 sact.sa_handler = default_signal_handler;
133 sigemptyset( &sact.sa_mask );
134 sact.sa_flags = 0;
135
136 if ( sigaction( s, &sact, &sig_rec->old_sigact ) < 0 )
137 #else
138 errno = 0;
139 sig_rec->ocallback = signal( s, default_signal_handler );
140 if ( sig_rec->ocallback == ( FLI_OSSIG_HANDLER ) - 1L || errno )
141 #endif
142 {
143 M_err( "fl_add_signal_callback", "Can't add handler for "
144 "signal %d", s );
145 fl_free( sig_rec );
146 return;
147 }
148 }
149
150 if ( fli_context->signal_rec )
151 sig_rec->next = fli_context->signal_rec;
152 fli_context->signal_rec = sig_rec;
153 }
154 }
155
156
157 /***************************************
158 ***************************************/
159
160 void
fl_remove_signal_callback(int s)161 fl_remove_signal_callback( int s )
162 {
163 FLI_SIGNAL_REC *last,
164 *rec = fli_context->signal_rec;
165
166 for ( last = rec; rec && rec->signum != s; last = rec, rec = rec->next )
167 /* empty */ ;
168
169 if ( ! rec )
170 {
171 M_err( "fl_remove_signal_callback", "No handler exists for signal %d",
172 s );
173 return;
174 }
175
176 if ( rec == fli_context->signal_rec )
177 fli_context->signal_rec = rec->next;
178 else
179 last->next = rec->next;
180
181 if ( ! sig_direct )
182 {
183 #if defined HAVE_SIGACTION
184 sigaction( s, &rec->old_sigact, NULL );
185 #else
186 signal( s, rec->ocallback );
187 #endif
188 }
189
190 fli_safe_free( rec );
191 }
192
193
194 /***************************************
195 ***************************************/
196
197 void
fl_signal_caught(int s)198 fl_signal_caught( int s )
199 {
200 FLI_SIGNAL_REC *rec = fli_context->signal_rec;
201
202 while ( rec && rec->signum != s )
203 rec = rec->next;
204
205 if ( ! rec )
206 {
207 M_err( "fl_signal_caught", "Caught bogus signal %d", s );
208 return;
209 }
210
211 rec->caught++;
212
213 #if ! defined HAVE_SIGACTION
214 if ( ! sig_direct && ! IsDangerous( s ) )
215 signal( s, default_signal_handler );
216 #endif
217 }
218
219
220 /***************************************
221 ***************************************/
222
223 void
fl_app_signal_direct(int y)224 fl_app_signal_direct( int y )
225 {
226 if ( ! fli_handle_signal )
227 fli_handle_signal = handle_signal;
228 sig_direct = y;
229 }
230
231
232 /***************************************
233 ***************************************/
234
235 void
fli_remove_all_signal_callbacks(void)236 fli_remove_all_signal_callbacks( void )
237 {
238 while ( fli_context->signal_rec )
239 fl_remove_signal_callback( fli_context->signal_rec->signum );
240 }
241
242
243 /*
244 * Local variables:
245 * tab-width: 4
246 * indent-tabs-mode: nil
247 * End:
248 */
249