2
Copyright (C) 1994 W. Schelter
4
This file is part of GNU Common Lisp, herein referred to as GCL
6
GCL is free software; you can redistribute it and/or modify it under
7
the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE as published by
8
the Free Software Foundation; either version 2, or (at your option)
11
GCL is distributed in the hope that it will be useful, but WITHOUT
12
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14
License for more details.
16
You should have received a copy of the GNU Library General Public License
17
along with GCL; see the file COPYING. If not, write to the Free Software
18
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
31
invoke_handler(int,int);
37
/* #include "arith.h" */
47
/* these sstructure pointers would need their structures provided...
48
so we just call them void */
53
unsigned long s4_neg_int[4],small_neg_int[3],small_pos_int[3];
58
We have two mechanisms for protecting against interrupts. 1] We have a
59
facility for delaying certain signals during critical regions of code.
60
This facility will involve BEGIN_NO_INTERRUPT and END_NO_INTERRUPT
64
handler_function_type our_signal_handler[32];
66
struct save_for_interrupt{
71
union lispunion buf[32];
72
struct call_data fcall;
73
object *vs_top,vs_topVAL,*vs_base;
74
struct bds_bd *bds_top,bds_topVAL;
75
struct invocation_history *ihs_top,ihs_topVAL;
77
char token_buf [4*INITIAL_TOKEN_LENGTH];
79
/* for storing the XS objects in te usig2_aux.c */
80
void *save_objects[75];
85
/* note these are the reverse of the ones in unixint.c
91
#define SS1(a,b) a = b ;
92
#define RS1(a,b) b = a ;
94
/* save objects in save_objects list */
98
char signals_handled [] = {SIGINT,SIGUSR2,SIGUSR1,SIGIO,SIGALRM,
99
#ifdef OTHER_SIGNALS_HANDLED
100
OTHER_SIGNALS_HANDLED
104
/* * in_signal_handler: if not zero indicates we are running inside a signal
105
handler, which may have been invoked at a random intruction, and so
106
it is not safe to do a relocatable gc.
108
* signals_pending: if (signals_pending & signal_mask(signo)) then this
109
signo 's handler is waiting to be run.
111
* signals_allowed: indicates the state we think we were in when
112
checking to invoke a signal. Values:
114
sig_none: definitely dont run handler
115
sig_normal: In principle `ok', but if desiring maximum safety dont run here.
116
sig_safe: safe point to run a function (eg make_cons,...)
117
sig_at_read: interrupting the getc function in read. Should be safe.
120
unwind (used by throw,return etc) resets this to sig_normal just as it
124
If we invoke signal handling routines at a storage
125
allocation pt, it is completely safe: we should save
126
some of the globals, but the freelists etc dont need
127
to be saved. pass: sig_safe to raise_pending.
129
If we invoke it at end of a No interrupts
130
region, then it we must look at whether these were nested.
131
We should probably have two endings for END_NO_INTERRUPTS,
132
one for when we want to raise, and one for where we are sure
133
we are at safe place. pass sig_use_signals_allowed_value
135
If we invoke a handler when at
136
signals_allowed == sig_at_read, then we are safe.
141
/* min safety level required for invoking a given signal handler */
142
char safety_required[]={XX,XX,XX,XX,XX,XX,XX,XX,
143
XX,XX,XX,XX,XX,XX,XX,XX,
144
XX,XX,XX,XX,XX,XX,XX,XX,
145
XX,XX,XX,XX,XX,XX,XX,XX};
148
gcl_init_safety(void)
149
{ safety_required[SIGINT]=sig_try_to_delay;
150
safety_required[SIGALRM]=sig_normal;
153
DO_INIT(gcl_init_safety();)
154
DEFUN_NEW("SIGNAL-SAFETY-REQUIRED",object,sSsignal_safety_required,SI,2,2,
155
NONE,OI,IO,OO,OO,(fixnum signo,fixnum safety),
156
"Set the safety level required for handling SIGNO to SAFETY, or if \
157
SAFETY is negative just return the current safety level for that \
158
signal number. Value of 1 means allow interrupt at any place not \
159
specifically marked in the code as bad, and value of 2 means allow it \
160
only in very SAFE places.")
162
{ if (signo > sizeof(safety_required))
163
{FEerror("Illegal signo:~a.",1,make_fixnum(signo));}
164
if (safety >=0) safety_required[signo] = safety;
165
return small_fixnum(safety_required[signo]) ;
171
main_signal_handler(int signo)
173
main_signal_handler(int signo, int a, int b)
175
{ int allowed = signals_allowed;
176
#ifdef NEED_TO_REINSTALL_SIGNALS
177
signal(signo,main_signal_handler);
179
if (allowed >= safety_required[signo])
180
{ signals_allowed = sig_none;
182
if (signo == SIGUSR1 ||
184
{ unblock_sigusr_sigio();}
186
invoke_handler(signo,allowed);
187
signals_allowed = allowed;
190
signals_pending |= signal_mask(signo);
196
static void before_interrupt(struct save_for_interrupt *p, int allowed);
197
static void after_interrupt(struct save_for_interrupt *p, int allowed);
199
/* caller saves and restores the global signals_allowed; */
201
invoke_handler(int signo, int allowed)
202
{struct save_for_interrupt buf;
203
before_interrupt(&buf,allowed);
204
signals_pending &= ~(signal_mask(signo));
205
{int prev_in_handler = in_signal_handler;
206
in_signal_handler |= (allowed <= sig_normal ? 1 : 0);
207
signals_allowed = allowed;
208
our_signal_handler[signo](signo);
210
in_signal_handler = prev_in_handler;
211
after_interrupt(&buf,allowed);
216
before_interrupt(struct save_for_interrupt *p, int allowed)
218
/* all this must be run in no interrupts mode */
219
if ( allowed < sig_safe)
220
{ /* save tht tops of the free stacks */
221
for(i=0; i < t_end ; i++)
222
{ struct typemanager *ad = &tm_table[i];
223
{SS1(p->free1[i],ad->tm_free);
225
{ char *beg = (char *) (p->free1[i]);
226
object x = (object)beg;
227
int amt = ad->tm_size;
228
SS1(p->free2[i],OBJ_LINK(p->free1[i]));
230
bcopy(beg ,&(p->buf[i]), amt);
234
{ x = (object) p->free2[i];
238
SS1(ad->tm_free,OBJ_LINK(p->free2[i]));
242
{ SS1(ad->tm_free, OBJ_LINK(p->free1[i]));
247
SS1(p->vs_top,vs_top);
248
SS1(p->vs_topVAL,*vs_top);
249
SS1(p->vs_base,vs_base);
250
SS1(p->bds_top,bds_top);
251
SS1(p->bds_topVAL,*bds_top);
252
SS1(p->ihs_top,ihs_top);
253
SS1(p->ihs_topVAL,*ihs_top);
254
{ void **pp = p->save_objects;
257
#define XS(a) *pp++ = (void *) (a);
258
#define XSI(a) *pp++ = (void *)(long)(a);
259
/* #define XS(a) *pp++ = * (void **) (&a); */
260
#include "usig2_aux.c"
261
if ((pp - (&(p->save_objects)[0])) >= (sizeof(p->save_objects)/sizeof(void *)))
264
#define MINN(a,b) (a<b?a :b)
265
p->token_st_dim = MINN(token->st.st_dim,tok_leng+1);
266
if (p->token_st_dim < sizeof(p->token_buf))
267
p->token_bufp = p->token_buf;
268
else { p->token_bufp= (void *)OUR_ALLOCA(p->token_st_dim);}
269
bcopy(token->st.st_self,p->token_bufp,p->token_st_dim);
274
after_interrupt(struct save_for_interrupt *p, int allowed)
276
/* all this must be run in no interrupts mode */
277
if ( allowed < sig_safe)
279
for(i=0; i < t_end ; i++)
280
{ struct typemanager *ad = &tm_table[i];
281
object current_fl = ad->tm_free;
282
{RS1(p->free1[i],ad->tm_free);
284
{ char *beg = (char *) (p->free1[i]);
285
object x = (object)beg;
286
int amt = ad->tm_size;
287
RS1(p->free2[i],(p->free1[i]));
288
if (x->d.m) error("should not be free");
289
bcopy(&(p->buf[i]),beg, amt);
291
{ x = (object) p->free2[i];
292
if (x->d.m) error("should not be free");
294
F_LINK(F_LINK(ad->tm_free)) = (long )current_fl;
301
else ad->tm_nfree =0;
305
RS1(p->vs_top,vs_top);
306
RS1(p->vs_topVAL,*vs_top);
307
RS1(p->vs_base,vs_base);
308
RS1(p->bds_top,bds_top);
309
RS1(p->bds_topVAL,*bds_top);
310
RS1(p->ihs_top,ihs_top);
311
RS1(p->ihs_topVAL,*ihs_top);
312
{ void **pp = p->save_objects;
316
/* #define XS(a) a = (void *)(*pp++)
317
We store back in the location 'a' the value we have saved.
320
/* #define XS(a) do { void **_p = (void **)(&a); *_p = (void *)(*pp++);}while(0) */
321
#define XS(a) a = (void *)(*pp++)
322
#define XSI(a) {union {void *v;long l;}u; u.v=*pp++; a = u.l;}
323
#include "usig2_aux.c"
326
bcopy(p->token_bufp,token->st.st_self,p->token_st_dim);
330
/* claim the following version of make_cons can be interrupted at any line
331
and is suitable for inlining.
335
/* MakeCons(object a, object b) */
336
/* { struct typemanager*ad = &tm_table[t_cons]; */
337
/* object new = (object) ad->tm_free; */
339
/* { new = alloc_object(t_cons); */
340
/* new->c.c_car = a; */
344
/* new->c.c_car=a; */
345
/* interrupt here and before_interrupt will copy new->c into the
346
C stack, so that a will be protected */
347
/* new->c.t=t_cons; */
349
/* Make interrupt copy new out to the stack and then zero new.
350
That way new is certainly gc valid, and its contents are protected.
351
So the above three operations can occur in any order.
354
/* { object tem = OBJ_LINK(new); */
356
interrupt here and we see that before_interrupt must save the top of the
357
free list AND the second thing on the Free list. That way we will be ok
358
here and an interrupt here could not affect tem. It is possible that tem
359
== 0, yet a gc happened in between. An interrupt here when tem = 0 would
360
mean the free list needs to be collected again by second gc.
362
/* ad->tm_free = tem; */
364
/* Whew: we got it safely off so interrupts can't hurt us now. */
365
/* ad->tm_nfree --; */
366
/* interrupt here and the cdr field will point to a f_link which is
367
a 'free' and so gc valid. b is still protected since
368
it is in the stack or a regiseter, and a is protected since it is
369
in new, and new is not free
372
/* new->c.c_cdr=b; */
377
/* COND is the condition where this is raised.
378
Might be sig_safe (eg at cons). */
381
raise_pending_signals(int cond)
382
{unsigned int allowed = signals_allowed ;
383
if (cond == sig_use_signals_allowed_value)
384
if (cond == sig_none || interrupt_enable ==0) return ;
388
{ unsigned int pending = signals_pending;
389
char *p = signals_handled;
392
{ if (signal_mask(*p) & pending
393
&& cond >= safety_required[(unsigned char)*p])
395
signals_pending &= ~(signal_mask(*p));
396
if (*p == SIGALRM && cond >= sig_safe)
399
invoke_handler(*p,cond);
404
signals_allowed = allowed;
409
DEFUN_NEW("ALLOW-SIGNAL",object,fSallow_signal,SI,1,1,NONE,OI,OO,OO,OO,(fixnum n),
410
"Install the default signal handler on signal N")
414
signals_allowed |= signal_mask(n);
415
unblock_signals(n,n);
416
/* sys v ?? just restore the signal ?? */
417
if (our_signal_handler[n])
418
{gcl_signal(n,our_signal_handler[n]);
419
return make_fixnum(1);
422
return make_fixnum(0);