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

本文发现了《APUE》一书中关于线程管理和daemon化进程中存在的两个BUG,并提供了修改后的代码实现。修正了线程管理函数中的指针错误及daemon化过程中因SIGHUP信号导致的进程退出问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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. voiddaemonize(constchar*cmd)
  7. {
  8. inti,fd0,fd1,fd2;
  9. pid_tpid;
  10. structrlimitrl;
  11. structsigactionsa;
  12. sigset_twaitmask;
  13. /*
  14. *Clearfilecreationmask.
  15. */
  16. umask(0);
  17. /*
  18. *Getmaximumnumberoffiledescriptors.
  19. */
  20. if(getrlimit(RLIMIT_NOFILE,&rl)<0)
  21. err_quit("%s:can'tgetfilelimit",cmd);
  22. /*
  23. *BecomeasessionleadertolosecontrollingTTY.
  24. */
  25. if((pid=fork())<0)
  26. err_quit("%s:can'tfork",cmd);
  27. elseif(pid!=0)/*parent*/
  28. exit(0);
  29. /*
  30. *Ensurefutureopenswon'tallocatecontrollingTTYs.
  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'tignoreSIGHUP");
  37. if((pid=fork())<0)
  38. err_quit("%s:can'tfork",cmd);
  39. elseif(pid!=0)/*parent*/
  40. exit(0);
  41. setsid();/*setsid在SIGHUP被忽略后执行,避免因系统对孤儿进程发送SIGHUP信号而导致进程退出。*/
  42. /*
  43. *Changethecurrentworkingdirectorytotherootso
  44. *wewon'tpreventfilesystemsfrombeingunmounted.
  45. */
  46. if(chdir("/")<0)
  47. err_quit("%s:can'tchangedirectoryto/");
  48. /*
  49. *Closeallopenfiledescriptors.
  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. *Attachfiledescriptors0,1,and2to/dev/null.
  57. */
  58. fd0=open("/dev/null",O_RDWR);
  59. fd1=dup(0);
  60. fd2=dup(0);
  61. /*
  62. *Initializethelogfile.
  63. */
  64. openlog(cmd,LOG_CONS,LOG_DAEMON);
  65. if(fd0!=0||fd1!=1||fd2!=2){
  66. syslog(LOG_ERR,"unexpectedfiledescriptors%d%d%d",
  67. fd0,fd1,fd2);
  68. exit(1);
  69. }
  70. /*我添加了以下三行*/
  71. sigemptyset(&waitmask);
  72. if(sigsuspend(&waitmask)!=-1)
  73. err_sys("sigsuspenderror");
  74. }
  75. /*还要添加一个main函数让代码跑起来。*/
  76. intmain(){
  77. daemonize("hellor,world");
  78. return0;
  79. }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值