Advanced Programming in UNIX Environment Episode 39

Reentrant Functions

When a signal that is being caught is handled by a process, the normal sequence of instructions being executed by the process is temporarily interrupted by the signal handler. The process then continues executing, but the instructions in the signal handler are now executed.

The Single UNIX Specification specifies the functions that are guaranteed to be safe to call from within a signal handler. These functions are reentrant and are called async-signal safe by the Single UNIX Specification. Besides being reentrant, they block any signals during operation if delivery of a signal might cause inconsistencies.

#include "apue.h"
#include <pwd.h>

static void my_alarm(nt signo)
{
    struct passwd *rootptr;

    printf("in signal handler\n");
    if((rootptr=getpwnam("root"))==NULL)
        err_sys("getpwnam(root) error");
    alarm(1);
}

int main(void)
{
    struct passwd *ptr;

    signal(SIGALRM, my_alarm);
    alarm(1);
    for( ; ; )
    {
        if((ptr=getpwnam("sar"))==NULL)
            err_sys("getpwnam error");
        if(strcmp(ptr->pw_name,"sar")!=0)
            printf("return value corrupted! pw_name=%s\n", ptr->pw_name);
    }
}

Call a nonreentrant function from a signal handler

SIGCLD Semantics

Two signals that continually generate confusion are SIGCLD and SIGCHLD. The name SIGCLD (without the H) is from System V, and this signal has different semantics from the BSD signal, named SIGCHLD. The POSIX.1 signal is also named SIGCHLD.

The semantics of the BSD SIGCHLD signal are normal, in the sense that its semantics are similar to those of all other signals. When the signal occurs, the status of a child has changed, and we need to call one of the wait functions to determine what has happened.

System V, however, has traditionally handled the SIGCLD signal differently from other signals. SVR4-based systems continue this questionable tradition (i.e., compatibility constraint) if we set its disposition using either signal or sigset (the older, SVR3-compatible functions to set the disposition of a signal). This older handling of SIGCLD consists of the following behavior:

1.If the process specifically sets its disposition to SIG_IGN, children of the calling
process will not generate zombie processes.

POSIX.1 does not specify what happens when SIGCHLD is ignored, so this behavior is allowed. The XSI option requires this behavior to be supported for SIGCHLD.
4.4BSD always generates zombies if SIGCHLD is ignored. If we want to avoid zombies, we have to wait for our children. With SVR4, if either signal or sigset is called to set the disposition of SIGCHLD to be ignored, zombies are never generated. All four platforms described in this book follow SVR4 in this behavior.
With sigaction, we can set the SA_NOCLDWAIT flag (Figure 10.16) to avoid zombies. This action is also supported on all four platforms.

2.If we set the disposition of SIGCLD to be caught, the kernel immediately checks whether any child processes are ready to be waited for and, if so, calls the SIGCLD handler.

#include "apue.h"
#include <sys/wait.h>

static void sig_cld(int);

int main(void)
{
    pid_t pid;

    if(signal(SIGCLD,sig_cld)==SIG_ERR)
        perror("signal error");
    if((pid=fork())<0)
        perror("fork error");
    else if(pid==0)
    {
        sleep(2);
        _exit(0);
    }

    pause();
    exit(0);
}

static void sig_cld(int signo)
{
    pid_t pid;
    int status;

    printf("SIGCLD received\n");

    if(signal(SIGCLD,sig_cld)=SIG_ERR)
        perror("signal error");
    if((pid=wait(&status))<0)
        perror("wait error");

    printf("pid=%d\n",pid);
}

System V SIGCLD handler that doesn’t work

FreeBSD 8.0 and Mac OS X 10.6.8 don’t exhibit this problem, because BSD-based systems generally don’t support historical System V semantics for SIGCLD. Linux 3.2.0 also doesn’t exhibit this problem, because it doesn’t call the SIGCHLD signal handler when a process arranges to catch SIGCHLD and child processes are ready to be waited for, even though SIGCLD and SIGCHLD are defined to be the same value. Solaris 10, on the other hand, does call the signal handler in this situation, but includes extra code in the kernel to avoid this problem.

POSIX.1 states that when we establish a signal handler for SIGCHLD and there exists a terminated child we have not yet waited for, it is unspecified whether the signal is generated. This allows the behavior described previously. But since POSIX.1 does not reset a signal’s disposition to its default when the signal occurs (assuming that we’re using the POSIX.1 sigaction function to set its disposition), there is no need for us to ever establish a signal handler for SIGCHLD within that handler.

Be cognizant of the SIGCHLD semantics for your implementation. Be especially
aware of some systems that #define SIGCHLD to be SIGCLD, or vice versa. Changing the name may allow you to compile a program that was written for another system, but if that program depends on the other semantics, it may not work.

Of the four platforms described in this text, only Linux 3.2.0 and Solaris 10 define SIGCLD. On these platforms, SIGCLD is equivalent to SIGCHLD.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值