又发现APUE第二版(中文版)的一个BUG
2008-12-13 23:25
639 查看
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):
#include "apue.h"
#include <syslog.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/resource.h>
void daemonize(const char *cmd)
{
int i, fd0, fd1, fd2;
pid_t pid;
struct rlimit rl;
struct sigaction sa;
sigset_t waitmask;
/*
* Clear file creation mask.
*/
umask(0);
/*
* Get maximum number of file descriptors.
*/
if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
err_quit("%s: can't get file limit", cmd);
/*
* Become a session leader to lose controlling TTY.
*/
if ((pid = fork()) < 0)
err_quit("%s: can't fork", cmd);
else if (pid != 0) /* parent */
exit(0);
/*
* Ensure future opens won't allocate controlling TTYs.
*/
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGHUP, &sa, NULL) < 0)
err_quit("%s: can't ignore SIGHUP");
if ((pid = fork()) < 0)
err_quit("%s: can't fork", cmd);
else if (pid != 0) /* parent */
exit(0);
setsid(); /*setsid在SIGHUP被忽略后执行,避免因系统对孤儿进程发送SIGHUP信号而导致进程退出。*/
/*
* Change the current working directory to the root so
* we won't prevent file systems from being unmounted.
*/
if (chdir("/") < 0)
err_quit("%s: can't change directory to /");
/*
* Close all open file descriptors.
*/
if (rl.rlim_max == RLIM_INFINITY)
rl.rlim_max = 1024;
for (i = 0; i < rl.rlim_max; i++)
close(i);
/*
* Attach file descriptors 0, 1, and 2 to /dev/null.
*/
fd0 = open("/dev/null", O_RDWR);
fd1 = dup(0);
fd2 = dup(0);
/*
* Initialize the log file.
*/
openlog(cmd, LOG_CONS, LOG_DAEMON);
if (fd0 != 0 || fd1 != 1 || fd2 != 2) {
syslog(LOG_ERR, "unexpected file descriptors %d %d %d",
fd0, fd1, fd2);
exit(1);
}
/*我添加了以下三行*/
sigemptyset(&waitmask);
if (sigsuspend(&waitmask) != -1)
err_sys("sigsuspend error");
}
/*还要添加一个main函数让代码跑起来。*/
int main() {
daemonize("hellor,world");
return 0;
}
函数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>
void daemonize(const char *cmd)
{
int i, fd0, fd1, fd2;
pid_t pid;
struct rlimit rl;
struct sigaction sa;
sigset_t waitmask;
/*
* Clear file creation mask.
*/
umask(0);
/*
* Get maximum number of file descriptors.
*/
if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
err_quit("%s: can't get file limit", cmd);
/*
* Become a session leader to lose controlling TTY.
*/
if ((pid = fork()) < 0)
err_quit("%s: can't fork", cmd);
else if (pid != 0) /* parent */
exit(0);
/*
* Ensure future opens won't allocate controlling TTYs.
*/
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGHUP, &sa, NULL) < 0)
err_quit("%s: can't ignore SIGHUP");
if ((pid = fork()) < 0)
err_quit("%s: can't fork", cmd);
else if (pid != 0) /* parent */
exit(0);
setsid(); /*setsid在SIGHUP被忽略后执行,避免因系统对孤儿进程发送SIGHUP信号而导致进程退出。*/
/*
* Change the current working directory to the root so
* we won't prevent file systems from being unmounted.
*/
if (chdir("/") < 0)
err_quit("%s: can't change directory to /");
/*
* Close all open file descriptors.
*/
if (rl.rlim_max == RLIM_INFINITY)
rl.rlim_max = 1024;
for (i = 0; i < rl.rlim_max; i++)
close(i);
/*
* Attach file descriptors 0, 1, and 2 to /dev/null.
*/
fd0 = open("/dev/null", O_RDWR);
fd1 = dup(0);
fd2 = dup(0);
/*
* Initialize the log file.
*/
openlog(cmd, LOG_CONS, LOG_DAEMON);
if (fd0 != 0 || fd1 != 1 || fd2 != 2) {
syslog(LOG_ERR, "unexpected file descriptors %d %d %d",
fd0, fd1, fd2);
exit(1);
}
/*我添加了以下三行*/
sigemptyset(&waitmask);
if (sigsuspend(&waitmask) != -1)
err_sys("sigsuspend error");
}
/*还要添加一个main函数让代码跑起来。*/
int main() {
daemonize("hellor,world");
return 0;
}
相关文章推荐
- 无聊的时候发现中文版XP一个无聊的bug
- 自定义ISAPI Filter中发现的一个与Keep-Alive相关的Bug
- Markdown使用时的一个BUG的发现过程
- 今天工作中发现一个问题,看算不算BUG,如何解释这种现象。
- 发现Chrome的一个bug
- 偶然的错误发现一个bug,引人深思的null
- 发现了《Oracle高效设计》中文版的一个问题
- 我ms发现了jquery的一个bug
- 居然发现了一个VS2012 C编译器 float的一个BUG!!!
- 由一个内存错误发现的cocos2dx 引擎3.4版本的 一个bug
- 又发现NIO的一个小Bug
- 发现ExtJs Chart的一个Bug
- 发现CSDN的一个Bug
- 貌似发现一个Visual Studio的BUG?
- 发现一个Bug
- 发现vs.net 2003的一个小bug~
- 偶然发现的android2.2的一个bug
- 发现一个骗粉丝的人后发现博客园的一个bug
- 如何写出一个让人很难发现的bug?
- 发现MonoRail+ActiveRecord的一个bug