Print this page
6805730 some simple changes would make 'init 5' much faster
6809492 startd shouldn't let hung subprocesses impede shutdown

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/svc/startd/fork.c
          +++ new/usr/src/cmd/svc/startd/fork.c
↓ open down ↓ 11 lines elided ↑ open up ↑
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22      - * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
       22 + * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  
  26   26  /*
  27   27   * fork.c - safe forking for svc.startd
  28   28   *
  29   29   * fork_configd() and fork_sulogin() are related, special cases that handle the
  30   30   * spawning of specific client processes for svc.startd.
  31   31   */
  32   32  
↓ open down ↓ 4 lines elided ↑ open up ↑
  37   37  #include <sys/types.h>
  38   38  #include <sys/uio.h>
  39   39  #include <sys/wait.h>
  40   40  #include <assert.h>
  41   41  #include <errno.h>
  42   42  #include <fcntl.h>
  43   43  #include <libcontract.h>
  44   44  #include <libcontract_priv.h>
  45   45  #include <libscf_priv.h>
  46   46  #include <limits.h>
       47 +#include <poll.h>
  47   48  #include <port.h>
  48   49  #include <signal.h>
  49   50  #include <stdarg.h>
  50   51  #include <stdio.h>
  51   52  #include <stdlib.h>
  52   53  #include <string.h>
  53   54  #include <unistd.h>
  54   55  #include <utmpx.h>
       56 +#include <spawn.h>
  55   57  
  56   58  #include "configd_exit.h"
  57   59  #include "protocol.h"
  58   60  #include "startd.h"
  59   61  
  60   62  static  struct  utmpx   *utmpp; /* pointer for getutxent() */
  61   63  
  62   64  pid_t
  63   65  startd_fork1(int *forkerr)
  64   66  {
↓ open down ↓ 606 lines elided ↑ open up ↑
 671  673                  pathenv = "PATH=/sbin:/usr/sbin:/usr/bin";
 672  674          else
 673  675                  pathenv = "PATH=/usr/sbin:/usr/bin";
 674  676  
 675  677          nenv = set_smf_env(NULL, 0, pathenv, NULL, NULL);
 676  678  
 677  679          (void) execle(path, path, arg, 0, nenv);
 678  680  
 679  681          perror("exec");
 680  682          exit(0);
      683 +}
      684 +
      685 +extern char **environ;
      686 +
      687 +/*
      688 + * A local variation on system(3c) which accepts a timeout argument.  This
      689 + * allows us to better ensure that the system will actually shut down.
      690 + *
      691 + * gracetime specifies an amount of time in seconds which the routine must wait
      692 + * after the command exits, to allow for asynchronous effects (like sent
      693 + * signals) to take effect.  This can be zero.
      694 + */
      695 +void
      696 +fork_with_timeout(const char *cmd, uint_t gracetime, uint_t timeout)
      697 +{
      698 +        int err = 0;
      699 +        pid_t pid;
      700 +        char *argv[4];
      701 +        posix_spawnattr_t attr;
      702 +        posix_spawn_file_actions_t factions;
      703 +
      704 +        sigset_t mask, savemask;
      705 +        uint_t msec_timeout;
      706 +        uint_t msec_spent = 0;
      707 +        uint_t msec_gracetime;
      708 +        int status;
      709 +
      710 +        msec_timeout = timeout * 1000;
      711 +        msec_gracetime = gracetime * 1000;
      712 +
      713 +        /*
      714 +         * See also system(3c) in libc.  This is very similar, except
      715 +         * that we avoid some unneeded complexity.
      716 +         */
      717 +        err = posix_spawnattr_init(&attr);
      718 +        if (err == 0)
      719 +                err = posix_spawnattr_setflags(&attr,
      720 +                    POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF |
      721 +                    POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP |
      722 +                    POSIX_SPAWN_NOEXECERR_NP);
      723 +
      724 +        /*
      725 +         * We choose to close fd's above 2, a deviation from system.
      726 +         */
      727 +        if (err == 0)
      728 +                err = posix_spawn_file_actions_init(&factions);
      729 +        if (err == 0)
      730 +                err = posix_spawn_file_actions_addclosefrom_np(&factions,
      731 +                    STDERR_FILENO + 1);
      732 +
      733 +        (void) sigemptyset(&mask);
      734 +        (void) sigaddset(&mask, SIGCHLD);
      735 +        (void) thr_sigsetmask(SIG_BLOCK, &mask, &savemask);
      736 +
      737 +        argv[0] = "/bin/sh";
      738 +        argv[1] = "-c";
      739 +        argv[2] = (char *)cmd;
      740 +        argv[3] = NULL;
      741 +
      742 +        if (err == 0)
      743 +                err = posix_spawn(&pid, "/bin/sh", &factions, &attr,
      744 +                    (char *const *)argv, (char *const *)environ);
      745 +
      746 +        (void) posix_spawnattr_destroy(&attr);
      747 +        (void) posix_spawn_file_actions_destroy(&factions);
      748 +
      749 +        if (err) {
      750 +                uu_warn("Failed to spawn %s: %s\n", cmd, strerror(err));
      751 +        } else {
      752 +                for (;;) {
      753 +                        int w;
      754 +                        w = waitpid(pid, &status, WNOHANG);
      755 +                        if (w == -1 && errno != EINTR)
      756 +                                break;
      757 +                        if (w > 0) {
      758 +                                /*
      759 +                                 * Command succeeded, so give it gracetime
      760 +                                 * seconds for it to have an effect.
      761 +                                 */
      762 +                                if (status == 0 && msec_gracetime != 0)
      763 +                                        (void) poll(NULL, 0, msec_gracetime);
      764 +                                break;
      765 +                        }
      766 +
      767 +                        (void) poll(NULL, 0, 100);
      768 +                        msec_spent += 100;
      769 +                        /*
      770 +                         * If we timed out, kill off the process, then try to
      771 +                         * wait for it-- it's possible that we could accumulate
      772 +                         * a zombie here since we don't allow waitpid to hang,
      773 +                         * but it's better to let that happen and continue to
      774 +                         * make progress.
      775 +                         */
      776 +                        if (msec_spent >= msec_timeout) {
      777 +                                uu_warn("'%s' timed out after %d "
      778 +                                    "seconds.  Killing.\n", cmd,
      779 +                                    timeout);
      780 +                                (void) kill(pid, SIGTERM);
      781 +                                (void) poll(NULL, 0, 100);
      782 +                                (void) kill(pid, SIGKILL);
      783 +                                (void) poll(NULL, 0, 100);
      784 +                                (void) waitpid(pid, &status, WNOHANG);
      785 +                                break;
      786 +                        }
      787 +                }
      788 +        }
      789 +        (void) thr_sigsetmask(SIG_BLOCK, &savemask, NULL);
 681  790  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX