又发现APUE第二版(中文版)的一个BUG

APUE是学习Linux编程最权威的一本书,但权威也不是绝对的。上周读到线程一章,在第304页发现一个BUG:
   函数foo_alloc(void)中:
         fp->f_next = h[idx];
         fh[idx] = fp->f_next;   改为  ==> fh[idx] = fp;
                       ^^^^^^^^^^^^^                       
      今天调试第344页的daemonize函数时又发现一个BUG,在damonize的最后加入 sigsuspend调用,再添加main函数让进程跑起来,编译后发现进程运行后立即退出,达不到damon进程的要求。 分析代码,发现是setsid()的位置不对。
      本书219页阐述了 setsid的三个作用:
               1> 该进程变成新会话首进程。
               2> 该进程成为一个新进程组的组长进程。
               3> 该进程没有控制终端。
      代码中调用setsid创建了一个只有一个进程的进程组,按书的代码,setsid之前,父进程已退出,那么setsid之后,子进程所在的进程组变成孤儿进程组,POSIX.1要求向新的孤儿进程组中处于停止状态的每一个进程发送挂断信号(SIGHUP),而系统对挂断信号的系统默认动作是终止该进程,所以在调用sigsuspend之后,进程接收SIGHUP信号便退出。
      
 我改写了书中的代码(程序清单13-1):
  1. #include "apue.h"
  2. #include <syslog.h>
  3. #include <fcntl.h>
  4. #include <signal.h>
  5. #include <sys/resource.h>
  6. void daemonize(const char *cmd)
  7. {
  8.     int                 i, fd0, fd1, fd2;
  9.     pid_t               pid;
  10.     struct rlimit       rl;
  11.     struct sigaction    sa;
  12.     sigset_t waitmask;
  13.     /*
  14.      * Clear file creation mask.
  15.      */
  16.     umask(0);
  17.     /*
  18.      * Get maximum number of file descriptors.
  19.      */
  20.     if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
  21.         err_quit("%s: can't get file limit", cmd);
  22.     /*
  23.      * Become a session leader to lose controlling TTY.
  24.      */
  25.     if ((pid = fork()) < 0)
  26.         err_quit("%s: can't fork", cmd);
  27.     else if (pid != 0) /* parent */
  28.         exit(0);
  29.     /*
  30.      * Ensure future opens won't allocate controlling TTYs.
  31.      */
  32.     sa.sa_handler = SIG_IGN;
  33.     sigemptyset(&sa.sa_mask);
  34.     sa.sa_flags = 0;
  35.     if (sigaction(SIGHUP, &sa, NULL) < 0)
  36.         err_quit("%s: can't ignore SIGHUP");
  37.     if ((pid = fork()) < 0)
  38.         err_quit("%s: can't fork", cmd);
  39.     else if (pid != 0) /* parent */
  40.         exit(0);
  41.     setsid();  /*setsid在SIGHUP被忽略后执行,避免因系统对孤儿进程发送SIGHUP信号而导致进程退出。*/
  42.     /*
  43.      * Change the current working directory to the root so
  44.      * we won't prevent file systems from being unmounted.
  45.      */
  46.     if (chdir("/") < 0)
  47.         err_quit("%s: can't change directory to /");
  48.     /*
  49.      * Close all open file descriptors.
  50.      */
  51.     if (rl.rlim_max == RLIM_INFINITY)
  52.         rl.rlim_max = 1024;
  53.     for (i = 0; i < rl.rlim_max; i++)
  54.         close(i);
  55.     /*
  56.      * Attach file descriptors 0, 1, and 2 to /dev/null.
  57.      */
  58.     fd0 = open("/dev/null", O_RDWR);
  59.     fd1 = dup(0);
  60.     fd2 = dup(0);
  61.     /*
  62.      * Initialize the log file.
  63.      */
  64.     openlog(cmd, LOG_CONS, LOG_DAEMON);
  65.     if (fd0 != 0 || fd1 != 1 || fd2 != 2) {
  66.         syslog(LOG_ERR, "unexpected file descriptors %d %d %d",
  67.           fd0, fd1, fd2);
  68.         exit(1);
  69.     }
  70.     /*我添加了以下三行*/
  71.     sigemptyset(&waitmask);
  72.     if (sigsuspend(&waitmask) != -1)
  73.         err_sys("sigsuspend error");
  74. }
  75. /*还要添加一个main函数让代码跑起来。*/
  76. int main() {
  77.     daemonize("hellor,world");   
  78.     return 0;
  79. }


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值