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):
函数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):
- #include"apue.h"
- #include<syslog.h>
- #include<fcntl.h>
- #include<signal.h>
- #include<sys/resource.h>
- voiddaemonize(constchar*cmd)
- {
- inti,fd0,fd1,fd2;
- pid_tpid;
- structrlimitrl;
- structsigactionsa;
- sigset_twaitmask;
- /*
- *Clearfilecreationmask.
- */
- umask(0);
- /*
- *Getmaximumnumberoffiledescriptors.
- */
- if(getrlimit(RLIMIT_NOFILE,&rl)<0)
- err_quit("%s:can'tgetfilelimit",cmd);
- /*
- *BecomeasessionleadertolosecontrollingTTY.
- */
- if((pid=fork())<0)
- err_quit("%s:can'tfork",cmd);
- elseif(pid!=0)/*parent*/
- exit(0);
- /*
- *Ensurefutureopenswon'tallocatecontrollingTTYs.
- */
- sa.sa_handler=SIG_IGN;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags=0;
- if(sigaction(SIGHUP,&sa,NULL)<0)
- err_quit("%s:can'tignoreSIGHUP");
- if((pid=fork())<0)
- err_quit("%s:can'tfork",cmd);
- elseif(pid!=0)/*parent*/
- exit(0);
- setsid();/*setsid在SIGHUP被忽略后执行,避免因系统对孤儿进程发送SIGHUP信号而导致进程退出。*/
- /*
- *Changethecurrentworkingdirectorytotherootso
- *wewon'tpreventfilesystemsfrombeingunmounted.
- */
- if(chdir("/")<0)
- err_quit("%s:can'tchangedirectoryto/");
- /*
- *Closeallopenfiledescriptors.
- */
- if(rl.rlim_max==RLIM_INFINITY)
- rl.rlim_max=1024;
- for(i=0;i<rl.rlim_max;i++)
- close(i);
- /*
- *Attachfiledescriptors0,1,and2to/dev/null.
- */
- fd0=open("/dev/null",O_RDWR);
- fd1=dup(0);
- fd2=dup(0);
- /*
- *Initializethelogfile.
- */
- openlog(cmd,LOG_CONS,LOG_DAEMON);
- if(fd0!=0||fd1!=1||fd2!=2){
- syslog(LOG_ERR,"unexpectedfiledescriptors%d%d%d",
- fd0,fd1,fd2);
- exit(1);
- }
- /*我添加了以下三行*/
- sigemptyset(&waitmask);
- if(sigsuspend(&waitmask)!=-1)
- err_sys("sigsuspenderror");
- }
- /*还要添加一个main函数让代码跑起来。*/
- intmain(){
- daemonize("hellor,world");
- return0;
- }