home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 10: Diskmags / nf_archive_10.iso / MAGS / PURE_B / PBMAG22A.MSA / MINT095S.ZIP / SRC / SIGNAL.C < prev    next >
C/C++ Source or Header  |  1987-04-22  |  14KB  |  522 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. /* signal.c:: signal handling routines */
  6.  
  7. #include "mint.h"
  8.  
  9. void (*sig_routine)();    /* used in intr.s */
  10.  
  11. /*
  12.  * killgroup(pgrp, sig): send a signal to all members of a process group
  13.  * returns 0 on success, or an error code on failure
  14.  */
  15.  
  16. long
  17. killgroup(pgrp, sig)
  18.     int pgrp, sig;
  19. {
  20.     PROC *p;
  21.     int found = 0;
  22.  
  23.     TRACE("killgroup %d %d", pgrp, sig);
  24.  
  25.     if (pgrp < 0)
  26.         return EINTRN;
  27.  
  28.     for (p = proclist; p; p = p->gl_next) {
  29.         if (p->pgrp == pgrp) {
  30.             post_sig(p, sig);
  31.             found++;
  32.         }
  33.     }
  34.     if (found) {
  35.         check_sigs();    /* see if the current process is affected */
  36.         return 0;
  37.     }
  38.     else {
  39.         DEBUG("killgroup: no processes found");
  40.         return EFILNF;
  41.     }
  42. }
  43.  
  44. /* post_sig: post a signal as being pending. It is assumed that the
  45.    caller has already verified that "sig" is a valid signal, and
  46.    moreover it is the caller's responsibility to call check_sigs()
  47.    if it's possible that p == curproc
  48.  */
  49.  
  50. void
  51. post_sig(p, sig)
  52.     PROC *p;
  53.     int sig;
  54. {
  55.     ulong sigm;
  56.  
  57. /* if process is ignoring this signal, do nothing
  58.  * also: signal 0 is SIGNULL, and should never be delivered through
  59.  * the normal channels (indeed, it's filtered out in dossig.c,
  60.  * but the extra sanity check here is harmless). The kernel uses
  61.  * signal 0 internally for some purposes, but it is handled
  62.  * specially (see supexec() in xbios.c, for example).
  63.  */
  64.     if (p->sighandle[sig] == SIG_IGN || sig == 0)
  65.         return;
  66.  
  67. /* if the process is already dead, do nothing */
  68.     if (p->wait_q == ZOMBIE_Q || p->wait_q == TSR_Q)
  69.         return;
  70.  
  71. /* mark the signal as pending */
  72.     sigm = (1L << (unsigned long)sig);
  73.     p->sigpending |= sigm;
  74.  
  75. /* if the signal is masked, do nothing further */
  76.     if ( (p->sigmask & sigm) != 0 )
  77.         return;
  78.  
  79. /* otherwise, make sure the process is awake */
  80.     if (p->wait_q && p->wait_q != READY_Q) {
  81.         rm_q(p->wait_q, p);
  82.         add_q(READY_Q, p);
  83.     }
  84. }
  85.  
  86. /*
  87.  * check_sigs: see if we have any signals pending. if so,
  88.  * handle them.
  89.  */
  90.  
  91. void
  92. check_sigs()
  93. {
  94.     ulong sigs, sigm;
  95.     ulong i;
  96.  
  97.     if (curproc->pid == 0) return;
  98.     sigs = curproc->sigpending & ~(curproc->sigmask);
  99.     if (sigs) {
  100.         sigm = 2;
  101.         for (i = 1; i < NSIG; i++) {
  102.             if (sigs & sigm) {
  103.                 ulong omask;
  104.  
  105.                 curproc->sigpending &= ~sigm;
  106.                 omask = curproc->sigmask;
  107.  
  108. /* sigextra gives which extra signals should also be masked */
  109.                 curproc->sigmask |= curproc->sigextra[i] | sigm;
  110.                 handle_sig(i);
  111.  
  112. /*
  113.  * POSIX.1-3.3.4.2(723) "If and when the user's signal handler returns
  114.  * normally, the original signal mask is restored."
  115.  *
  116.  * BUG?: This unmasking could unmask a pending signal which we will not
  117.  * see this time around (if the signal number is less than i) and which
  118.  * was not pending when we started; should we detect this condition and
  119.  * loop around for a second try? POSIX only guarantees delivery of
  120.  * one signal per kernel entry, so this shouldn't really be a problem.
  121.  */
  122.                 curproc->sigmask = omask;    /* unmask signals */
  123.             }
  124.             sigm = sigm << 1;
  125.         }
  126.     }
  127. }
  128.  
  129. /*
  130.  * raise: cause a signal to be raised in the current process
  131.  */
  132.  
  133. void
  134. raise(sig)
  135.     int sig;
  136. {
  137.     post_sig(curproc, sig);
  138.     check_sigs();
  139. }
  140.  
  141. #ifdef EXCEPTION_SIGS
  142. /* exception numbers corresponding to signals */
  143. char excep_num[NSIG] =
  144. { 0, 0, 0, 0,
  145.   4,            /* SIGILL == illegal instruction */
  146.   9,            /* SIGTRAP == trace trap    */
  147.   4,            /* pretend SIGABRT is also illegal instruction */
  148.   8,            /* SIGPRIV == privileged instruction exception */
  149.   5,            /* SIGFPE == divide by zero */
  150.   0, 2,            /* SIGBUS == bus error */
  151.   3            /* SIGSEGV == address error */
  152. /* everything else gets zeros */
  153. };
  154.  
  155. /* a "0" means we don't print a message when it happens -- typically the
  156.    user is expecting a synchronous signal, so we don't need to report it
  157. */
  158.  
  159. const char *signames[NSIG] = { 0,
  160. 0, 0, 0, "ILLEGAL INSTRUCTION", "TRACE TRAP",
  161. 0, "PRIVILEGE VIOLATION", "DIVISION BY ZERO", 0, "BUS ERROR",
  162. "ADDRESS ERROR", "BAD SYSTEM CALL", 0, 0, 0,
  163. 0, 0, 0, 0, 0,
  164. 0, 0, 0, "CPU TIME EXHAUSTED", "FILE TOO BIG",
  165. 0, 0, 0, 0, 0
  166. };
  167.  
  168. /*
  169.  * replaces the TOS "show bombs" routine: for now, print the name of the
  170.  * interrupt on the console, and save info on the crash in the appropriate
  171.  * system area
  172.  */
  173.  
  174. void
  175. bombs(sig)
  176.     int sig;
  177. {
  178.     long *procinfo = (long *)0x380L;
  179.     int i;
  180.     CONTEXT *crash;
  181.  
  182.     if (signames[sig]) {
  183.         ALERT("%s: User PC=%lx (basepage=%lx)",
  184.             signames[sig],
  185.             curproc->ctxt[SYSCALL].pc, curproc->base);
  186.  
  187. /* save the processor state at crash time */
  188. /* assumes that "crash time" is the context curproc->ctxt[SYSCALL] */
  189. /* BUG: this is not true if the crash happened in the kernel; in the
  190.  * latter case, the crash context wasn't saved anywhere.
  191.  */
  192.         crash = &curproc->ctxt[SYSCALL];
  193.         *procinfo++ = 0x12345678;    /* magic flag for valid info */
  194.         for (i = 0; i < 15; i++)
  195.             *procinfo++ = crash->regs[i];
  196.         *procinfo++ = crash->ssp;
  197.         *procinfo++ = ((long)excep_num[sig]) << 24L;
  198.         *procinfo++ = crash->usp;
  199.  
  200. /* we're also supposed to save some info from the supervisor stack. it's not
  201.  * clear what we should do for MiNT, since most of the stuff that used to be
  202.  * on the stack has been put in the CONTXT struct. Moreover, we don't want
  203.  * to crash because of an attempt to access illegal memory. Hence, we do
  204.  * nothing here...
  205.  */
  206.     }
  207. }
  208. #endif
  209.  
  210. /*
  211.  * handle_sig: do whatever is appropriate to handle a signal
  212.  */
  213.  
  214. static long unwound_stack = 0;
  215.  
  216. void
  217. handle_sig(sig)
  218.     int sig;
  219. {
  220.     long oldstack, newstack;
  221.     long *stack;
  222.     CONTEXT *call, oldsysctxt, newcurrent;
  223.     extern void sig_return();
  224.  
  225.     if (curproc->sighandle[sig] == SIG_IGN)
  226.         return;
  227.     else if (curproc->sighandle[sig] == SIG_DFL) {
  228. _default:
  229.         switch(sig) {
  230. #if 0
  231. /* Note: SIGNULL is filtered out in dossig.c and is never actually
  232.  * delivered (its only purpose for the user is to test for the existence of
  233.  * a process, it isn't a real signal). The kernel uses SIGNULL
  234.  * internally, but all such code does the signal handling "by hand"
  235.  * and so no default handling is necessary.
  236.  */
  237.             case SIGNULL:
  238. #endif
  239.             case SIGWINCH:
  240.             case SIGCHLD:
  241.                 return;        /* do nothing */
  242.             case SIGSTOP:
  243.             case SIGTSTP:
  244.             case SIGTTIN:
  245.             case SIGTTOU:
  246.                 stop(sig);
  247.                 return;
  248.             case SIGCONT:
  249.                 curproc->sigpending &= ~STOPSIGS;
  250.                 return;
  251.  
  252. /* here are the fatal signals. for SIGINT, we use p_term() so that
  253.  * TOS programs that catch ^C via the vector at 0x400 will work. for
  254.  * other signals (especially SIGKILL) we don't want that to happen;
  255.  * TOS programs aren't prepared to deal with signals.
  256.  */
  257.             case SIGINT:        /* ^C */
  258.                 if (curproc->domain == DOM_TOS) {
  259.                     curproc->sigmask &= ~(1L<<SIGINT);
  260.                     p_term(-32);
  261.                     return;
  262.                 }
  263.                 /* otherwise, fall through */
  264.             default:
  265. #ifdef EXCEPTION_SIGS
  266.                 bombs(sig); /* tell the user what happened */
  267. #endif
  268.                 terminate(sig << 8, ZOMBIE_Q);
  269.         }
  270.     }
  271.     else {        /* user wants to handle it himself */
  272.  
  273. /* another kludge: there is one case in which the p_sigreturn mechanism
  274.  * is invoked by the kernel, namely when the user calls Supexec()
  275.  * or when s/he installs a handler for the GEMDOS terminate vector (#0x102)
  276.  * and the program terminates. MiNT fakes the call to user code with
  277.  * signal 0 (SIGNULL); programs that longjmp out of the user function
  278.  * and are later sent back to it again (e.g. if ^C keeps getting pressed
  279.  * and a terminate vector has been installed) will grow the stack without
  280.  * bound unless we watch for this case.
  281.  *
  282.  * Solution (sort of): whenever Pterm() is called, we unwind the
  283.  * stack; otherwise, we let it grow, so that nested Supexec()
  284.  * calls work.
  285.  *
  286.  * Note that SIGNULL is thrown away when sent by user processes, 
  287.  * and the user can't mask it (it's UNMASKABLE), so there is
  288.  * is no possibility of confusion with anything the user does.
  289.  */
  290.         if (sig == 0) {
  291.     /* p_term() sets sigmask to let us know to do Psigreturn */
  292.             if (curproc->sigmask & 1L) {
  293.                 p_sigreturn();
  294.                 curproc->sigmask &= ~1L;
  295.             } else {
  296.                 unwound_stack = 0;
  297.             }
  298.         }
  299.  
  300.         call = &curproc->ctxt[SYSCALL];
  301. /*
  302.  * what we do is build two fake stack frames; the bottom one is
  303.  * for a call to the user function, with (long)parameter being the
  304.  * signal number; the top one is for sig_return.
  305.  * When the user function returns, it returns to sig_return, which
  306.  * calls into the kernel to restore the context in prev_ctxt
  307.  * (thus putting us back here). We can then continue on our way.
  308.  */
  309.  
  310. /* set a new system stack, with a bit of buffer space */
  311.         oldstack = curproc->sysstack;
  312.         newstack = ((long) ( (&newcurrent) - 3 )) - 12;
  313.  
  314.         if (newstack < (long)curproc->stack + ISTKSIZE + 256) {
  315.             ALERT("stack overflow");
  316.             goto _default;
  317.         }
  318.         else if ((long) curproc->stack + STKSIZE < newstack) {
  319.             FATAL("system stack not in proc structure");
  320.         }
  321.  
  322. /* unwound_stack is set by p_sigreturn() */
  323.         if (sig == 0 && unwound_stack)
  324.             curproc->sysstack = unwound_stack;
  325.         else
  326.             curproc->sysstack = newstack;
  327.         oldsysctxt = *call;
  328.         stack = (long *)(call->sr & 0x2000 ? call->ssp :
  329.                 call->usp);
  330. /*
  331.    Hmmm... here's another potential problem for the signal 0 terminate
  332.    vector: if the program keeps returning back to user mode without
  333.    worrying about the supervisor stack, we'll eventually overflow it.
  334.    However, if the program is in supervisor mode itself, then we don't
  335.    want to stomp on its stack. Temporary solution: ignore the problem,
  336.    the stack's only growing 8 bytes at a time.
  337.  */
  338.         *(--stack) = (long)sig;
  339.         *(--stack) = (long)sig_return;
  340.         if (call->sr & 0x2000)
  341.             call->ssp = ((long) stack);
  342.         else
  343.             call->usp = ((long) stack);
  344.         call->pc = (long) curproc->sighandle[sig];
  345.  
  346.         ((long *)curproc->sysstack)[1] = FRAME_MAGIC;
  347.         ((long *)curproc->sysstack)[2] = oldstack;
  348.         ((long *)curproc->sysstack)[3] = sig;
  349.  
  350.         if (save_context(&newcurrent) == 0 ) {
  351. /*
  352.  * go do the signal; eventually, we'll restore this context (unless the
  353.  * user longjmp'd out of his signal handler). while the user is handling
  354.  * the signal, it's masked out to prevent race conditions. p_sigreturn()
  355.  * will unmask it for us when the user is finished.
  356.  */
  357.             newcurrent.regs[0] = CTXT_MAGIC;
  358.                 /* set D0 so next return is different */
  359.             assert(curproc->magic == CTXT_MAGIC);
  360.             leave_kernel();
  361.             restore_context(call);
  362.         }
  363. /*
  364.  * OK, we get here from p_sigreturn, via the user returning from
  365.  * the handler to sig_return. Restoring the stack and unmasking the
  366.  * signal have been done already for us by p_sigreturn.
  367.  * We should just restore the old system call context
  368.  * and continue with whatever it was we were doing.
  369.  */
  370.         TRACE("done handling signal");
  371.         curproc->ctxt[SYSCALL] = oldsysctxt;
  372.         assert(curproc->magic == CTXT_MAGIC);
  373.     }
  374. }
  375.  
  376. /*
  377.  * the p_sigreturn system call
  378.  * When called by the user from inside a signal handler, it indicates a
  379.  * desire to restore the old stack frame prior to a longjmp() out of
  380.  * the handler.
  381.  * When called from the sig_return module, it indicates that the user
  382.  * is finished a handler, and we should not only restore the stack
  383.  * frame but also the old context we were working in (which is on the
  384.  * system call stack -- see handle_sig).
  385.  * The "valid_return" variable is 0 in the first case, 1 in the second.
  386.  */
  387.  
  388. short valid_return;
  389.  
  390. long
  391. p_sigreturn()
  392. {
  393.     CONTEXT *oldctxt;
  394.     long *frame;
  395.     long sig;
  396.  
  397.     unwound_stack = 0;
  398. top:
  399.     frame = (long *)curproc->sysstack;
  400.     frame++;    /* frame should point at FRAME_MAGIC, now */
  401.     sig = frame[2];
  402.     if (*frame != FRAME_MAGIC || (sig < 0) || (sig >= NSIG)) {
  403.         FATAL("Psigreturn: system stack corrupted");
  404.     }
  405.     if (frame[1] == 0) {
  406.         DEBUG("Psigreturn: frame at %lx points to 0", frame-1);
  407.         return 0;
  408.     }
  409.     unwound_stack = curproc->sysstack;
  410.     TRACE("Psigreturn(%d)", (int)sig);
  411.  
  412.     curproc->sysstack = frame[1];    /* restore frame */
  413.     curproc->sigmask &= ~(1L<<sig); /* unblock signal */
  414.  
  415.     if (!valid_return) {
  416. /* here, the user is telling us that a longjmp out of a signal handler is
  417.  * about to occur; so we should unwind *all* the signal frames
  418.  */
  419.         goto top;
  420.     }
  421.     else {
  422.         valid_return = 0;
  423.         oldctxt = ((CONTEXT *)(&frame[2])) + 3;
  424.         if (oldctxt->regs[0] != CTXT_MAGIC) {
  425.             FATAL("p_sigreturn: corrupted context");
  426.         }
  427.         assert(curproc->magic == CTXT_MAGIC);
  428.         restore_context(oldctxt);
  429.         return 0;    /* dummy -- this isn't reached */
  430.     }
  431. }
  432.  
  433. /*
  434.  * stop a process because of signal "sig"
  435.  */
  436.  
  437. void
  438. stop(sig)
  439.     int sig;
  440. {
  441.     unsigned int code;
  442.     unsigned long oldmask;
  443.     PROC *p;
  444.  
  445.     code = sig << 8;
  446.  
  447.     if (curproc->pid == 0) {
  448.         ALERT("attempt to stop MiNT");
  449.         return;
  450.     }
  451.  
  452. /* notify parent */
  453.     p = pid2proc(curproc->ppid);
  454.     if (p && !(p->sigflags[SIGCHLD] & SA_NOCLDSTOP)) {
  455.         post_sig(p, SIGCHLD);
  456.     }
  457.  
  458.     oldmask = curproc->sigmask;
  459.  
  460. /* mask out most signals */
  461.     curproc->sigmask |= ~(UNMASKABLE | SIGTERM);
  462.  
  463. /* sleep until someone signals us awake */
  464.     sleep(STOP_Q, (long) code | 0177);
  465.  
  466. /* when we wake up, restore the signal mask */
  467.     curproc->sigmask = oldmask;
  468.  
  469. /* and discard any signals that would cause us to stop again */
  470.     curproc->sigpending &= ~STOPSIGS;
  471. }
  472.  
  473. /*
  474.  * interrupt handlers to raise SIGBUS, SIGSEGV, etc. Note that for
  475.  * really fatal errors we reset the handler to SIG_DFL, so that
  476.  * a second such error kills us
  477.  */
  478.  
  479. void
  480. exception(sig)
  481.     int sig;
  482. {
  483.     curproc->sighandle[sig] = SIG_DFL;
  484.     raise(sig);
  485. }
  486.  
  487. void
  488. sigbus()
  489. {
  490.     exception(SIGBUS);
  491. }
  492.  
  493. void
  494. sigaddr()
  495. {
  496.     exception(SIGSEGV);
  497. }
  498.  
  499. void
  500. sigill()
  501. {
  502.     exception(SIGILL);
  503. }
  504.  
  505. void
  506. sigpriv()
  507. {
  508.     raise(SIGPRIV);
  509. }
  510.  
  511. void
  512. sigfpe()
  513. {
  514.     raise(SIGFPE);
  515. }
  516.  
  517. void
  518. sigtrap()
  519. {
  520.     raise(SIGTRAP);
  521. }
  522.