简体   繁体   中英

why my signal handler wait no just child process?

my code is a multiprocess concurrent server process,it use system V message queue to communicate with client process,one client with one child process. first i want wait child process which is not use any more.and when i set SIGCHLD handler with SIG_IGN,the program can work correct,but always mistake when i catch SIGCHLD, the mistake is client process blocked in mesrcv system call,which means server don't send message to client . second , the server process went out when i enter ^\\ to quit my client process ,i made it become a daemon and make it run in backgroud forever,so i think maybe the waitpid calling are wait itself?although i think it's impossible

//this is signal handler
void handler(int sig){
    waitpid(-1,NULL,WNOHANG);
}
//in main
//my first step is make it become a daemon(fork twice)
//my first step is using record lock to ensure only one running
//then set signal handler and process message send by client
if(signal(SIGCHLD,SIG_IGN)==SIG_ERR){
    //because its a daemon,so no tty and redirct stdin,stdout,stderr to /dev/null
    syslog(LOG_ERR|LOG_USER,"set signal handler failed");
    return errno;
}
//now process the client request ,client message contant a client sysV message queue id and a filename,server report the file whether exist
int pid;
while((rcv_size=msgrcv(srvmqid,&srvbuf,1024,0)!=-1){
    if(0==rcv_size)
        continue;
    if((pid=fork())<=0){
        clibuf.mtype=srvbuf.mtype;
        climsqid=strtol(srvbuf.filename,&filename,10);
        if((fd=open(filename,O_RDONLY)==-1)
            snprintf(clibuf.filename,"file doesn't exist\n");
        else{
            snprintf(clibuf.filename,"file exist\n");
            close(fd);
        }
        if(msgsnd(climsqid,&clibuf,1024,0)==-1)
            syslog(LOG_ERR,"send message to client pid:%d failed,srvbuf.mtype);
        if(pid==0)    //if pid<0,then no child process is created
            exit(0);
    }

}

the core code of client process are below

int main(int argc,char*argv[]){
//first ,i create the client message queue and open public serve message queue,then send struct msgbuf struct to server,the mtype is pid,the buffer behind mtype is composed by client message queue key and filename(no space between them)
while(1){
if(msgsnd(sermsqid,&sndbuf,1024,0)!=-1){
    if(msgrcv(climsqid,&rcvbuf,1024,0,0)!=-1)
        printf("type:%ld,file state:%s\n",rcvbuf.mtype,rcvbuf.filename);
    else
        printf("receive message failed\n");
}
printf("input a filename you want to search:(^e to quit)");
fgets(filename,1024,stdin);
if(filename[0]==5)//^e is 5
    break;
filename[strlen(filename)-1)='\0';
snprintf(sndbuf.filename,1024,"%d%s",climsqid,filename);
}
msgctl(climsqid,IPC_RMID,NULL);
return errno;
}

This code doesn't allow error handling or restarting the call after it's interrupted:

while((rcv_size=msgrcv(srvmqid,&srvbuf,1024,0)!=-1){
    ...

You don't properly handle msgrcv() being interrupted and needing to be called again.

Per the POSIX msgrcv() documentation :

ERRORS

The msgrcv() function shall fail if:

...

[EINTR] The msgrcv() function was interrupted by a signal.

Note the Linux msgrcv() man page states:

If no message of the requested type is available and IPC_NOWAIT isn't specified in msgflg , the calling process is blocked until one of the following conditions occurs:

  • A message of the desired type is placed in the queue.

  • The message queue is removed from the system. In this case, the system call fails with errno set to EIDRM .

  • The calling process catches a signal. In this case, the system call fails with errno set to EINTR . ( msgrcv() is never automatically restarted after being interrupted by a signal handler, regardless of the setting of the SA_RESTART flag when establishing a signal handler.)

What does this style of code achieve:

while((rcv_size=msgrcv(srvmqid,&srvbuf,1024,0)!=-1){

So you save some lines of code. Were you selling a textbook with lots of code in it, the saved lines of code would mean a few pages less per book, saving a few pennies. Over enough copies, that pays for the publisher's swimming pool.

Stuffing everything into a conditional like that is really, really bad. There's nothing gained over explicitly using multiple lines of code:

for ( ;; )
{
    ssize_t rcv_size;
    do
    {
        errno = 0;
        rcv_size = msgrcv(...);
    }
    while ( ( -1 == rcv_size ) && ( EINTR == errno ) );

    if ( -1 == rcv_size )
    {
        perror( "msgrcv()" );
        break;
    }
    else if ( 0 == rcv_size )
    {
        continue;
    }
    ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM