This is usig2.c in view mode; [Download] [Up]
/*
Copyright (C) 1994 W. Schelter
This file is part of GNU Common Lisp, herein referred to as GCL
GCL is free software; you can redistribute it and/or modify it under
the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GCL is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU Library General Public License
along with GCL; see the file COPYING. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef IN_UNIXINT
#define NEED_MP_H
#include "include.h"
#include <signal.h>
#include "usig.h"
#include "arith.h"
#endif
/* these sstructure pointers would need their structures provided...
so we just call them void */
void * sfaslp;
#ifdef CMAC
EXTER
unsigned long s4_neg_int[4],small_neg_int[3],small_pos_int[3];
#endif
tes()
{void *buf[70];
void **p=buf;
#define XS(a) *p++ = (void *) (a)
#include "usig2_aux.c"
}
/*
We have two mechanisms for protecting against interrupts. 1] We have a
facility for delaying certain signals during critical regions of code.
This facility will involve BEGIN_NO_INTERRUPT and END_NO_INTERRUPT
*/
handler_function_type our_signal_handler[32];
struct save_for_interrupt{
object free1[32];
object free2[32];
object altfree1[32];
object altfree2[32];
union lispunion buf[32];
struct call_data fcall;
object *vs_top,vs_topVAL,*vs_base;
struct bds_bd *bds_top,bds_topVAL;
struct invocation_history *ihs_top,ihs_topVAL;
char *token_bufp;
char token_buf [4*INITIAL_TOKEN_LENGTH];
int token_st_dim;
/* for storing the XS objects in te usig2_aux.c */
void *save_objects[75];
};
/* note these are the reverse of the ones in unixint.c
... uggghhh*/
#undef SS1
#undef RS1
#define SS1(a,b) a = b ;
#define RS1(a,b) b = a ;
/* save objects in save_objects list */
char signals_handled [] = {SIGINT,SIGUSR2,SIGUSR1,SIGIO,SIGALRM,0};
/* * in_signal_handler: if not zero indicates we are running inside a signal
handler, which may have been invoked at a random intruction, and so
it is not safe to do a relocatable gc.
* signals_pending: if (signals_pending & signal_mask(signo)) then this
signo 's handler is waiting to be run.
* signals_allowed: indicates the state we think we were in when
checking to invoke a signal. Values:
sig_none: definitely dont run handler
sig_normal: In principle `ok', but if desiring maximum safety dont run here.
sig_safe: safe point to run a function (eg make_cons,...)
sig_at_read: interrupting the getc function in read. Should be safe.
unwind (used by throw,return etc) resets this to sig_normal just as it
does the longjmp.
/* If we invoke signal handling routines at a storage
allocation pt, it is completely safe: we should save
some of the globals, but the freelists etc dont need
to be saved. pass: sig_safe to raise_pending.
If we invoke it at end of a No interrupts
region, then it we must look at whether these were nested.
We should probably have two endings for END_NO_INTERRUPTS,
one for when we want to raise, and one for where we are sure
we are at safe place. pass sig_use_signals_allowed_value
If we invoke a handler when at
signals_allowed == sig_at_read, then we are safe.
*/
#define XX sig_safe
/* min safety level required for invoking a given signal handler */
char safety_required[]={XX,XX,XX,XX,XX,XX,XX,XX,
XX,XX,XX,XX,XX,XX,XX,XX,
XX,XX,XX,XX,XX,XX,XX,XX,
XX,XX,XX,XX,XX,XX,XX,XX};
int
init_safety()
{ safety_required[SIGINT]=sig_try_to_delay;
safety_required[SIGALRM]=sig_normal;
}
DO_INIT(init_safety();)
DEFUN("SIGNAL-SAFETY-REQUIRED",int,sSsignal_safety_required,SI,2,2,
NONE,II,IO,OO,OO,
"Set the safety level required for handling SIGNO to SAFETY, or if \
SAFETY is negative just return the current safety level for that \
signal number. Value of 1 means allow interrupt at any place not \
specifically marked in the code as bad, and value of 2 means allow it \
only in very SAFE places.")
(signo,safety)
{ if (signo > sizeof(safety_required))
{FEerror("Illegal signo:~a.",1,make_fixnum(signo));}
if (safety >=0) safety_required[signo] = safety;
return safety_required[signo] ;
}
void
main_signal_handler(signo, a,b)
int signo,a,b;
{ int allowed = signals_allowed;
#ifdef NEED_TO_REINSTALL_SIGNALS
signal(signo,main_signal_handler);
#endif
if (allowed >= safety_required[signo])
{ signals_allowed = sig_none;
if (signo == SIGUSR1 ||
signo == SIGIO)
{ unblock_sigusr_sigio();}
invoke_handler(signo,allowed);
signals_allowed = allowed;
}
else {
signals_pending |= signal_mask(signo);
alarm(1);}
return;
}
static void before_interrupt();
static void after_interrupt();
/* caller saves and restores the global signals_allowed; */
invoke_handler(signo,allowed)
int signo,allowed;
{struct save_for_interrupt buf;
before_interrupt(&buf,allowed);
signals_pending &= ~(signal_mask(signo));
{int prev_in_handler = in_signal_handler;
in_signal_handler |= (allowed <= sig_normal ? 1 : 0);
signals_allowed = allowed;
our_signal_handler[signo](signo);
signals_allowed = 0;
in_signal_handler = prev_in_handler;
after_interrupt(&buf,allowed);
}}
int tok_leng;
static void
before_interrupt(p,allowed)
struct save_for_interrupt *p;
int allowed;
{int i;
/* all this must be run in no interrupts mode */
if ( allowed < sig_safe)
{ /* save tht tops of the free stacks */
for(i=0; i < t_end ; i++)
{ struct typemanager *ad = &tm_table[i];
{SS1(p->free1[i],ad->tm_free);
if (p->free1[i])
{ char *beg = (char *) (p->free1[i]);
object x = (object)beg;
int amt = ad->tm_size;
SS1(p->free2[i],FL_LINK(p->free1[i]));
ad->tm_nfree --;
bcopy(beg ,&(p->buf[i]), amt);
bzero(beg+8,amt-8);
x->d.m = 0;
if (p->free2[i])
{ x = (object) p->free2[i];
beg = (char *)x;
x->d.m = 0;
bzero(beg+8,amt-8);
SS1(ad->tm_free,FL_LINK(p->free2[i]));
ad->tm_nfree --;
}
else
{ SS1(ad->tm_free,FL_LINK(p->free1[i]));
}}
}}
}
SS1(p->fcall,fcall);
SS1(p->vs_top,vs_top);
SS1(p->vs_topVAL,*vs_top);
SS1(p->vs_base,vs_base);
SS1(p->bds_top,bds_top);
SS1(p->bds_topVAL,*bds_top);
SS1(p->ihs_top,ihs_top);
SS1(p->ihs_topVAL,*ihs_top);
{ void **pp = p->save_objects;
#undef XS
#define XS(a) *pp++ = (void *) (a);
#include "usig2_aux.c"
if ((pp - (&(p->save_objects)[0])) >= (sizeof(p->save_objects)/sizeof(void *)))
abort();
}
#define MINN(a,b) (a<b?a :b)
p->token_st_dim = MINN(token->st.st_dim,tok_leng+1);
if (p->token_st_dim < sizeof(p->token_buf))
p->token_bufp = p->token_buf;
else { p->token_bufp= OUR_ALLOCA(p->token_st_dim);}
bcopy(token->st.st_self,p->token_bufp,p->token_st_dim);
}
static void
after_interrupt(p,allowed)
struct save_for_interrupt *p;
int allowed;
{int i;
/* all this must be run in no interrupts mode */
if ( allowed < sig_safe)
{
for(i=0; i < t_end ; i++)
{ struct typemanager *ad = &tm_table[i];
object current_fl = ad->tm_free;
{RS1(p->free1[i],ad->tm_free);
if (p->free1[i])
{ char *beg = (char *) (p->free1[i]);
object x = (object)beg;
int amt = ad->tm_size;
RS1(p->free2[i],FL_LINK(p->free1[i]));
if (x->d.m) error("should not be free");
bcopy(&(p->buf[i]),beg, amt);
if (p->free2[i])
{ x = (object) p->free2[i];
if (x->d.m) error("should not be free");
x->d.m = FREE;
FL_LINK(FL_LINK(ad->tm_free)) = current_fl;
ad->tm_nfree += 2;
}
else
ad->tm_nfree =1;
}
else ad->tm_nfree =0;
}}
}
RS1(p->fcall,fcall);
RS1(p->vs_top,vs_top);
RS1(p->vs_topVAL,*vs_top);
RS1(p->vs_base,vs_base);
RS1(p->bds_top,bds_top);
RS1(p->bds_topVAL,*bds_top);
RS1(p->ihs_top,ihs_top);
RS1(p->ihs_topVAL,*ihs_top);
{ void **pp = p->save_objects;
#undef XS
/* #define XS(a) ((void *)a) = *pp++ */
#define XS(a) a = (void *)(*pp++)
#include "usig2_aux.c"
}
bcopy(p->token_bufp,token->st.st_self,p->token_st_dim);
}
/* claim the following version of make_cons can be interrupted at any line
and is suitable for inlining.
*/
object
MakeCons(a,b)
object a,b;
{ struct typemanager*ad = &tm_table[t_cons];
object new = (object) ad->tm_free;
if (new == 0)
{ new = alloc_object(t_cons);
new->c.c_car = a;
goto END;
}
new->c.c_car=a;
/* interrupt here and before_interrupt will copy new->c into the
C stack, so that a will be protected */
new->c.t=t_cons;
new->c.m= 0;
/* Make interrupt copy new out to the stack and then zero new.
That way new is certainly gc valid, and its contents are protected.
So the above three operations can occur in any order.
*/
{ object tem = FL_LINK(new);
/*
interrupt here and we see that before_interrupt must save the top of the
free list AND the second thing on the Free list. That way we will be ok
here and an interrupt here could not affect tem. It is possible that tem
== 0, yet a gc happened in between. An interrupt here when tem = 0 would
mean the free list needs to be collected again by second gc.
*/
ad->tm_free = tem;
}
/* Whew: we got it safely off so interrupts can't hurt us now. */
ad->tm_nfree --;
/* interrupt here and the cdr field will point to a f_link which is
a 'free' and so gc valid. b is still protected since
it is in the stack or a regiseter, and a is protected since it is
in new, and new is not free
*/
END:
new->c.c_cdr=b;
return new;
}
/* COND is the condition where this is raised.
Might be sig_safe (eg at cons). */
void
raise_pending_signals(cond)
int cond;
{unsigned int allowed = signals_allowed ;
if (cond == sig_use_signals_allowed_value)
{ cond == allowed ;}
if (cond == sig_none || interrupt_enable ==0) return ;
AGAIN:
{ unsigned int pending = signals_pending;
char *p = signals_handled;
if (pending)
while(*p)
{ if (signal_mask(*p) & pending
&& cond >= safety_required[*p])
{
signals_pending &= ~(signal_mask(*p));
if (*p == SIGALRM && cond >= sig_safe)
{ alarm(0);}
else
invoke_handler(*p,cond);
goto AGAIN;
}
p++;
}
signals_allowed = allowed;
return;
}}
DEFUN("ALLOW-SIGNAL",int,fSallow_signal,SI,1,1,NONE,II,OO,OO,OO,
"Install the default signal handler on signal N")
(n)
int n;
{int ma ;
int ans = 0;
signals_allowed |= signal_mask(n);
unblock_signals(n,n);
/* sys v ?? just restore the signal ?? */
if (our_signal_handler[n])
{gcl_signal(n,our_signal_handler[n]);
return 1;
}
else
return 0;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.