#include "include.h"
#include <signal.h>
#include "usig.h"

char handled [] = {SIGINT,SIGUSR2,SIGUSR1,SIGALRM,0};

void
main_signal_handler(signo, a,b)
     int signo,a,b;
{ unsigned long mask = signal_mask(signo) ;
  /* todo:  fix this so that a signal can't interrupt the
     before_interrupt routines!!
  */     
  if( mask && signals_allowed)
    {struct save_for_interrupt buf;
     BEGIN_NO_INTERRUPT;
     before_interrupt(&buf);
     signals_pending &= ~mask;
     signals_allowed = 1;
     our_signal_handler[signo](signo,a,b);
     after_interrupt(&buf);
     END_NO_INTERRUPT;
    }
  else signals_pending |= mask;
  return;
}


#define SS1(a,b) a = b ;
#define RS1(a,b) b = a ;

before_interrupt(p)
   struct save_for_interrupt *p;
{int i;
 /* all this must be run in no interrupts mode */
  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]));
	   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 -= 2;
	     }
	   else
	     { SS1(ad->tm_free,FL_LINK(p->free1[i]));
	       ad->tm_nfree -= 1;
	     }}
       }}
  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);
}


after_interrupt(p)
  struct save_for_interrupt *p;
{int i;
 /* all this must be run in no interrupts mode */
  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)) = 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);

}


/* 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;
}

object siLcdefn;
/*  a hack here to test interrupt robustness...
    send self sigalarms...constantly and call a function
*//*    
void
sigalrm()
{
  if (siLcdefn->s.s_dbind &&
      siLcdefn->s.s_dbind != Cnil)
    IapplyVector(siLcdefn->s.s_dbind,0,0);
    
}
*/
void
raise_pending_signals()
{AGAIN:
  { unsigned int pending = signals_pending;
   unsigned int allowed = signals_allowed;
   char *p = handled;
   if (signals_allowed)
     while(*p)
       { if (signal_mask(*p) & pending)
	   {main_signal_handler(*p);
	    goto AGAIN;}
	   p++;
	 }
   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);
#ifdef HAVE_SIGVEC
  ma = sigblock(0);
  ans = sigsetmask(ma & ~(sigmask(n)));
#else
 /* sys v ?? just restore the signal ?? */
 if (our_signal_handler[n])
  ans = signal(n,main_signal_handler);
#endif 
 return ans;
}
