Logo Search packages:      
Sourcecode: ksh version File versions

trap.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1984-2007 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * make signal traps
 */

#include "make.h"

#include <sig.h>

#undef      trap

#if defined(SIGIOT) && SIGIOT == SIGEMT
#undef      SIGIOT
#endif

struct Alarms_s; typedef struct Alarms_s Alarms_t;

struct Alarms_s
{
      Alarms_t*   next;
      Rule_t*           rule;
      Seconds_t   time;
};

static int  signals[] =       /* signals to catch           */
{
      SIGHUP,
      SIGINT,
      SIGALRM,
      SIGTERM,
      SIGPIPE,
#ifdef SIGILL
      SIGILL,
#endif
#ifdef SIGIOT
      SIGIOT,
#endif
#ifdef SIGEMT
      SIGEMT,
#endif
#if !DEBUG
      SIGQUIT,
#ifdef SIGBUS
      SIGBUS,
#endif
#ifdef SIGSEGV
      SIGSEGV,
#endif
#endif
#ifdef SIGUSR1
      SIGUSR1,
#endif
#ifdef SIGUSR2
      SIGUSR2,
#endif
};

static struct Trap_s
{
      int*        caught;           /* caught signals       */
      Alarms_t*   alarms;           /* sorted alarm list          */
      Alarms_t*   freealarms; /* free alarm list            */
} trap;

/*
 * catch and mark interrupts
 */

static void
interrupt(register int sig)
{
      signal(sig, sig == SIGPIPE ? SIG_IGN : interrupt);
      trap.caught[sig] = 1;
      state.caught = 1;
}

/*
 * (re)initialize wakeup rule pointers
 */

void
initwakeup(int repeat)
{
      register Alarms_t*      a;

      NoP(repeat);
      for (a = trap.alarms; a; a = a->next)
            a->rule = makerule(a->rule->name);
}

/*
 * set next wakeup time
 */

static void
setwakeup(void)
{
      register Seconds_t      t;
      register Seconds_t      now;
      int               level;

      now = CURSECS;
      if (!trap.alarms)
            t = 0;
      else if (trap.alarms->time <= now)
            t = 1;
      else
            t = trap.alarms->time - now;
      alarm(t);
      sfsprintf(tmpname, MAXNAME, "%lu", t ? (now + t) : t);
      setvar(internal.alarm->name, fmtelapsed(t, 1), 0);
      if (error_info.trace <= (level = (state.test & 0x00010000) ? 2 : CMDTRACE))
      {
            register Alarms_t*      a;

            if (a = trap.alarms)
            {
                  error(level, "ALARM  TIME                 RULE");
                  do
                  {
                        error(level, "%6s %s %s", fmtelapsed((a->time >= now) ? (a->time - now) : 0, 1), timestr(tmxsns(a->time, 0)), a->rule->name);
                  } while (a = a->next);
            }
            else
                  error(level, "ALARM -- NONE");
      }
}

/*
 * wakeup in t seconds and make rules in p
 * t==0 to drop alarms for list p, all for p==0
 */

void
wakeup(Seconds_t t, register List_t* p)
{
      register Alarms_t*      a;
      register Alarms_t*      z;
      register Alarms_t*      x;
      Alarms_t*         alarms;
      Seconds_t         now;

      alarms = trap.alarms;
      now = CURSECS;
      if (t)
      {
            t += now;
            if (!p)
                  p = cons(catrule(external.interrupt, ".", fmtsignal(-SIGALRM), 1), NiL);
      }
      if (p)
      {
            do
            {
                  x = 0;
                  for (z = 0, a = trap.alarms; a; z = a, a = a->next)
                        if (a->rule == p->rule)
                        {
                              x = a;
                              if (z)
                                    z->next = a->next;
                              else
                                    trap.alarms = a->next;
                              break;
                        }
                  if (t)
                  {
                        if (!x)
                        {
                              if (x = trap.freealarms)
                                    trap.freealarms = trap.freealarms->next;
                              else
                                    x = newof(0, Alarms_t, 1, 0);
                              x->rule = p->rule;
                        }
                        x->time = t;
                        x->next = 0;
                        for (z = 0, a = trap.alarms; a; z = a, a = a->next)
                              if (t <= a->time)
                              {
                                    x->next = a;
                                    break;
                              }
                        if (z)
                              z->next = x;
                        else
                              trap.alarms = x;
                  }
            } while (p = p->next);
      }
      else if (a = trap.alarms)
      {
            trap.alarms = 0;
            while (x = a->next)
                  a = x;
            a->next = trap.freealarms;
            trap.freealarms = a;
      }
      if (trap.alarms != alarms)
            setwakeup();
}

/*
 * initialize the traps
 */

void
inittrap(void)
{
      register int      i;

      memfatal();
      trap.caught = newof(0, int, sig_info.sigmax + 1, 0);
      for (i = 0; i < elementsof(signals); i++)
            if (signal(signals[i], interrupt) == SIG_IGN)
                  signal(signals[i], SIG_IGN);
}

/*
 * handle interrupts
 * called by trap() in safe regions
 * 0 returned if no interrupts to handle
 */

int
handle(void)
{
      register int            sig;
      register Rule_t*  r;
      register Alarms_t*      a;
      char*             s;
      char*             w;
      Var_t*                  v;
      Seconds_t         t;

      if (!state.caught)
            return 0;
      while (state.caught)
      {
            state.caught = 0;
            for (sig = 1; sig <= sig_info.sigmax; sig++)
                  if (trap.caught[sig])
                  {
                        trap.caught[sig] = 0;

                        /*
                         * flush the output streams
                         */

                        sfsync(sfstderr);
                        sfsync(sfstdout);

                        /*
                         * continue if already in finish
                         */

                        if (state.finish)
                        {
                              if (!state.interrupt)
                                    state.interrupt = sig;
                              for (sig = 1; sig <= sig_info.sigmax; sig++)
                                    trap.caught[sig] = 0;
                              return 0;
                        }

                        /*
                         * check user trap (some cannot be trapped)
                         */

                        w = 0;
                        if (!state.compileonly)
                              switch (sig)
                              {
                              case SIGALRM:
                                    s = fmtsignal(-sig);
                                    t = CURSECS;
                                    while ((a = trap.alarms) && a->time <= t)
                                    {
                                          trap.alarms = a->next;
                                          r = a->rule;
                                          a->next = trap.freealarms;
                                          trap.freealarms = a;
                                          maketop(r, (P_dontcare|P_force|P_ignore|P_repeat)|((r->property & P_make)?0:P_foreground), s);
                                    }
                                    setwakeup();
                                    continue;
                              default:
                                    s = fmtsignal(-sig);
                                    if ((r = catrule(external.interrupt, ".", s, 0)) || (r = getrule(external.interrupt)))
                                    {
                                          if (!(r->property & P_functional))
                                                v = setvar(external.interrupt, s, 0);
                                          maketop(r, (P_dontcare|P_force|P_ignore|P_repeat)|((r->property & P_make)?0:P_foreground), s);
                                          if (r->property & P_functional)
                                                v = getvar(r->name);
                                          w = v->value;
                                          if (r->status == EXISTS && (streq(w, s) || streq(w, "continue")))
                                          {
                                                message((-1, "trap %s handler %s status CONTINUE return %s", s, r->name, w));
                                                continue;
                                          }
                                          message((-1, "trap %s handler %s status TERMINATE return %s", s, r->name, w));
                                    }
                                    /*FALLTHROUGH*/
#ifdef SIGILL
                              case SIGILL:
#endif
#ifdef SIGIOT
                              case SIGIOT:
#endif
#ifdef SIGEMT
                              case SIGEMT:
#endif
#ifdef SIGBUS
                              case SIGBUS:
#endif
#ifdef SIGSEGV
                              case SIGSEGV:
#endif
                                    break;
                              }

                        /*
                         * terminate outstanding jobs
                         */

                        terminate();

                        /*
                         * the interpreter resumes without exit
                         */

                        if (state.interpreter)
                        {
                              if (state.waiting)
                                    return 1;
                              longjmp(state.resume.label, 1);
                        }

                        /*
                         * if external.interrupt=""|"exit" then exit
                         * otherwise terminate via original signal
                         */

                        if (w && (!*w || streq(w, "exit")))
                              state.interrupt = 0;
                        else if (!state.interrupt)
                              state.interrupt = sig;
                        finish(3);

                        /*
                         * shouldn't get here
                         */

                        exit(3);
                  }
      }
      return 1;
}

Generated by  Doxygen 1.6.0   Back to index