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