MonetDB 捕捉信号

MonetDB运行在Unix系统上,就需要进行一些系统的捕捉和处理。下列是常见的几种信号:

SIGCHLD:在一个进程终止或停止时,将SIGCHLD信号发送给父进程。信号捕捉函数中通常要调用一种wait函数取得子进程ID和其终止的状态。
SIGHUP:通常此信号通知守护进程,以重新读取它们的配置文件。
SIGINT:当用户按中断键(一般是DELETE或Ctrl+C)时,终端驱动程序产生此信号并送至前台进程组中的每一个进程。
SIGKILL:这是不能被捕捉或忽略的信号之一。它向系统管理员提供了一种可以杀死任一进程的可靠方法。
SIGQUIT:当用户在终端上按退出键(Ctrl+)时,产生此信号,并送至前台进程组中的所有进程。此信号不仅会终止前台进程组,同时还会产生一个core文件。
UNIX的处理信号集的操作:

1
2
3
4
5
6
    #include <signal.h>
  int sigemptyset(sigset_t *set);
  int sigfillset(sigset_t *set);
  int sigaddset(sigset_t *set, int signo);
  int sigdelset(sigset_t *set, int signo);
  int sigismember(sonct sigset_T *set,int signo);

UNIX sigaction函数的功能是检查和修改与指定信号相关联的处理动作。

1
2
3
4
5
6
7
8
9
    #include <signal.h>
  int sigaction(int signo, const struct sigaction* restrict act,
                                  struct sigaction *restrict oact);
  struct sigaction{
      void (*sa_handler)(int);     /*addr of signal handler*/
      sigset_t sa_mask;           /*or SIG_IGN,or SIG_DFL*/
      int     sa_flags;            /*signal options*/
      void (*sa_sigaction)(int, siginfo_t *, void *);   /*alternate handler*/
  }

下面是MonetDB捕捉SIGINT,SIGQUIT,SIGTERM信号的代码,处理的是handler函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    sigemptyset(&sa.sa_mask);
  sa.sa_flags = 0;
  sa.sa_handler = handler;
  if (
          sigaction(SIGINT, &sa, NULL) == -1 ||
          sigaction(SIGQUIT, &sa, NULL) == -1 ||
          sigaction(SIGTERM, &sa, NULL) == -1)
  {
      Mfprintf(oerr, "%s: FATAL: unable to create signal handlers: %s\n",
              argv[0], strerror(errno));
      MERO_EXIT(1);
  }
/**
 * Handler for SIGINT, SIGTERM and SIGQUIT.  This starts a graceful
 * shutdown of merovingian.*/
void  handler(int sig)
{
  char *signame = sigtostr(sig);
  if (signame == NULL) {
      Mfprintf(stdout, "caught signal %d, starting shutdown sequence\n", sig);
  } else {
      Mfprintf(stdout, "caught %s, starting shutdown sequence\n", signame);
  }
  _mero_keep_listening = 0;
}

捕捉SIGHUP信号,处理是huphandler函数,重新读取配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    sigemptyset(&sa.sa_mask);
  sa.sa_flags = 0;
  sa.sa_handler = huphandler;
  if (sigaction(SIGHUP, &sa, NULL) == -1) {
      Mfprintf(oerr, "%s: FATAL: unable to create signal handlers: %s\n",
              argv[0], strerror(errno));
      MERO_EXIT(1);
  }
/**
 * Handler for SIGHUP, causes a re-read of the .merovingian_properties
 * file and the logfile to be reopened.
 */
void huphandler(int sig)
{
  int t;
  time_t now = time(NULL);
  struct tm *tmp = localtime(&now);
  char mytime[20];
  char *f;
  confkeyval *kv;

  (void)sig;

  /* re-read properties, we're in our dbfarm */
  readProps(_mero_props, ".");

  /* check and trim the hash-algo from the passphrase for easy use
  * lateron */
  kv = findConfKey(_mero_props, "passphrase");
  if (kv->val != NULL) {
      char *h = kv->val + 1;
      if ((f = strchr(h, '}')) == NULL) {
          setConfVal(kv, NULL);
      } else {
          *f = '\0';
          if (strcmp(h, MONETDB5_PASSWDHASH) != 0) {
              setConfVal(kv, NULL);
          } else {
              setConfVal(kv, f + 1);
          }
      }
  }

  /* have to make sure the logger is not logging anything */
  pthread_mutex_lock(&_mero_topdp_lock);

  strftime(mytime, sizeof(mytime), "%Y-%m-%d %H:%M:%S", tmp);

  f = getConfVal(_mero_props, "logfile");
  /* reopen (or open new) file */
  t = open(f, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
  if (t == -1) {
      Mfprintf(stderr, "forced to ignore SIGHUP: unable to open "
              "'%s': %s\n", f, strerror(errno));
  } else {
      Mfprintf(_mero_logfile, "%s END merovingian[" LLFMT "]: "
              "caught SIGHUP, closing logfile\n",
              mytime, (long long int)_mero_topdp->next->pid);
      fflush(_mero_logfile);
      _mero_topdp->out = _mero_topdp->err = t;
      _mero_logfile = fdopen(t, "a");
      Mfprintf(_mero_logfile, "%s BEG merovingian[" LLFMT "]: "
              "reopening logfile\n",
              mytime, (long long int)_mero_topdp->next->pid);
  }

  /* logger go ahead! */
  pthread_mutex_unlock(&_mero_topdp_lock);
}

捕捉SIGCHLD信号,处理childhandler,处理释放子进程的资源和清理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
    sa.sa_flags = SA_SIGINFO;
  sigemptyset(&sa.sa_mask);
  sa.sa_sigaction = childhandler;
  if (sigaction(SIGCHLD, &sa, NULL) == -1) {
      Mfprintf(oerr, "%s: FATAL: unable to create signal handlers: %s\n",
              argv[0], strerror(errno));
      MERO_EXIT(1);
  }
/**
 * Handles SIGCHLD signals, that is, signals that a parent receives
 * about its children.  This handler deals with terminated children, by
 * deregistering them from the internal administration (_mero_topdp)
 * with the necessary cleanup.
 */
void  childhandler(int sig, siginfo_t *si, void *unused)
{
  dpair p, q;

  (void)sig;
  (void)unused;

  /* wait for the child to get properly terminated, hopefully filling
  * in the siginfo struct on FreeBSD */
  wait(NULL);

  if (si->si_code != CLD_EXITED &&
          si->si_code != CLD_KILLED &&
          si->si_code != CLD_DUMPED)
  {
      /* ignore traps, stops and continues, we only want terminations
      * of the client process */
      return;
  }
  pthread_mutex_lock(&_mero_topdp_lock);

  /* get the pid from the former child, and locate it in our list */
  q = _mero_topdp->next;
  p = q->next;
  while (p != NULL) {
      if (p->pid == si->si_pid) {
          /* log everything that's still in the pipes */
          logFD(p->out, "MSG", p->dbname, (long long int)p->pid, _mero_logfile);
          /* remove from the list */
          q->next = p->next;
          /* close the descriptors */
          close(p->out);
          close(p->err);
          if (si->si_code == CLD_EXITED) {
              Mfprintf(stdout, "database '%s' (%lld) has exited with "
                      "exit status %d\n", p->dbname,
                      (long long int)p->pid, si->si_status);
          } else if (si->si_code == CLD_KILLED) {
              char *sigstr = sigtostr(si->si_status);
              char signum[8];
              if (sigstr == NULL) {
                  snprintf(signum, 8, "%d", si->si_status);
                  sigstr = signum;
              }
              Mfprintf(stdout, "database '%s' (%lld) was killed by signal "
                      "%s\n", p->dbname,
                      (long long int)p->pid, sigstr);
          } else if (si->si_code == CLD_DUMPED) {
              Mfprintf(stdout, "database '%s' (%lld) has crashed "
                      "(dumped core)\n", p->dbname,
                      (long long int)p->pid);
          }
          if (p->dbname)
              free(p->dbname);
          free(p);
          pthread_mutex_unlock(&_mero_topdp_lock);
          return;
      }
      q = p;
      p = q->next;
  }

  pthread_mutex_unlock(&_mero_topdp_lock);

  Mfprintf(stdout, "received SIGCHLD from unknown child with pid %lld\n",
          (long long int)si->si_pid);
}

Comments