Beispiel #1
0
/* This is called at main or AST level. It is at AST level for DONTWAITFORCHILD
   and at main level otherwise. In any case it is called when a child process
   terminated. At AST level it won't get interrupted by anything except a
   inner mode level AST.
*/
int
vmsHandleChildTerm(struct child *child)
{
  int status;
  register struct child *lastc, *c;
  int child_failed;

  vms_jobsefnmask &= ~(1 << (child->efn - 32));

  lib$free_ef (&child->efn);
  if (child->comname)
    {
      if (!ISDB (DB_JOBS) && !ctrlYPressed)
        unlink (child->comname);
      free (child->comname);
    }

  (void) sigblock (fatal_signal_mask);

  child_failed = !(child->cstatus & 1 || ((child->cstatus & 7) == 0));

  /* Search for a child matching the deceased one.  */
  lastc = 0;
#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
  for (c = children; c != 0 && c != child; lastc = c, c = c->next)
    ;
#else
  c = child;
#endif

  if (child_failed && !c->noerror && !ignore_errors_flag)
    {
      /* The commands failed.  Write an error message,
         delete non-precious targets, and abort.  */
      child_error (c, c->cstatus, 0, 0, 0);
      c->file->update_status = us_failed;
      delete_child_targets (c);
    }
  else
    {
      if (child_failed)
        {
          /* The commands failed, but we don't care.  */
          child_error (c, c->cstatus, 0, 0, 1);
          child_failed = 0;
        }

#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
      /* If there are more commands to run, try to start them.  */
      start_job (c);

      switch (c->file->command_state)
        {
        case cs_running:
          /* Successfully started.  */
          break;

        case cs_finished:
          if (c->file->update_status != us_success)
            /* We failed to start the commands.  */
            delete_child_targets (c);
          break;

        default:
          OS (error, NILF,
              _("internal error: '%s' command_state"), c->file->name);
          abort ();
          break;
        }
#endif /* RECURSIVEJOBS */
    }

  /* Set the state flag to say the commands have finished.  */
  c->file->command_state = cs_finished;
  notice_finished_file (c->file);

#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
  /* Remove the child from the chain and free it.  */
  if (lastc == 0)
    children = c->next;
  else
    lastc->next = c->next;
  free_child (c);
#endif /* RECURSIVEJOBS */

  /* There is now another slot open.  */
  if (job_slots_used > 0)
    --job_slots_used;

  /* If the job failed, and the -k flag was not given, die.  */
  if (child_failed && !keep_going_flag)
    die (EXIT_FAILURE);

  (void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));

  return 1;
}
Beispiel #2
0
RETSIGTYPE
fatal_error_signal (int sig)
{
#ifdef __MSDOS__
    extern int dos_status, dos_command_running;

    if (dos_command_running)
    {
        /* That was the child who got the signal, not us.  */
        dos_status |= (sig << 8);
        return;
    }
    remove_intermediates (1);
    exit (EXIT_FAILURE);
#else /* not __MSDOS__ */
#ifdef _AMIGA
    remove_intermediates (1);
    if (sig == SIGINT)
        fputs (_("*** Break.\n"), stderr);

    exit (10);
#else /* not Amiga */
#ifdef WINDOWS32
    extern HANDLE main_thread;

    /* Windows creates a sperate thread for handling Ctrl+C, so we need
       to suspend the main thread, or else we will have race conditions
       when both threads call reap_children.  */
    if (main_thread)
    {
        DWORD susp_count = SuspendThread (main_thread);

        if (susp_count != 0)
            fprintf (stderr, "SuspendThread: suspend count = %ld\n", susp_count);
        else if (susp_count == (DWORD)-1)
        {
            DWORD ierr = GetLastError ();

            fprintf (stderr, "SuspendThread: error %ld: %s\n",
                     ierr, map_windows32_error_to_string (ierr));
        }
    }
#endif
    handling_fatal_signal = 1;

    /* Set the handling for this signal to the default.
       It is blocked now while we run this handler.  */
    signal (sig, SIG_DFL);

    /* A termination signal won't be sent to the entire
       process group, but it means we want to kill the children.  */

    if (sig == SIGTERM)
    {
        struct child *c;
        for (c = children; c != 0; c = c->next)
            if (!c->remote)
                (void) kill (c->pid, SIGTERM);
    }

    /* If we got a signal that means the user
       wanted to kill make, remove pending targets.  */

    if (sig == SIGTERM || sig == SIGINT
#ifdef SIGHUP
            || sig == SIGHUP
#endif
#ifdef SIGQUIT
            || sig == SIGQUIT
#endif
       )
    {
        struct child *c;

        /* Remote children won't automatically get signals sent
        to the process group, so we must send them.  */
        for (c = children; c != 0; c = c->next)
            if (c->remote)
                (void) remote_kill (c->pid, sig);

        for (c = children; c != 0; c = c->next)
            delete_child_targets (c);

        /* Clean up the children.  We don't just use the call below because
        we don't want to print the "Waiting for children" message.  */
        while (job_slots_used > 0)
            reap_children (1, 0);
    }
    else
        /* Wait for our children to die.  */
        while (job_slots_used > 0)
            reap_children (1, 1);

    /* Delete any non-precious intermediate files that were made.  */

    remove_intermediates (1);

#ifdef SIGQUIT
    if (sig == SIGQUIT)
        /* We don't want to send ourselves SIGQUIT, because it will
           cause a core dump.  Just exit instead.  */
        exit (EXIT_FAILURE);
#endif

#ifdef WINDOWS32
    if (main_thread)
        CloseHandle (main_thread);
    /* Cannot call W32_kill with a pid (it needs a handle).  The exit
       status of 130 emulates what happens in Bash.  */
    exit (130);
#else
    /* Signal the same code; this time it will really be fatal.  The signal
       will be unblocked when we return and arrive then to kill us.  */
    if (kill (getpid (), sig) < 0)
        pfatal_with_name ("kill");
#endif /* not WINDOWS32 */
#endif /* not Amiga */
#endif /* not __MSDOS__  */
}