帶超時的system

工作中,需要使用tftp等協議下載一些文件,但這時候遇到一個問題就是當tftp的服務器沒有打開時,system函數會阻塞較長時間(長達數秒),這時候首先想到的就是設置tftp的超時參數,但因爲還有很多協議也有超時返回的需求,我就想一勞永逸的封裝一個函數來完成這項任務.最後決定重寫一下system並設置超時參數,封裝的函數如下(system_timeout).這裏需要解釋進行兩層封裝的原因:在system_timeout中我們將_system_timeout進行了一層封裝,並將信號SIGCHLD設置爲SIG_DFL是因爲我們在_system_timeout中調用了waitpid,而這個函數在SIGCHLD被忽略是會產生ECHILD錯誤,手冊解釋如下:
ERRORS
       ECHILD (for  waitpid() or waitid()) The process specified by pid (wait-
          pid()) or idtype and id (waitid()) does not exist or  is  not  a
          child  of  the  calling process.  (This can happen for one’s own
          child if the action for SIGCHLD is set to SIG_IGN.  See also the
          Linux Notes section about threads.)
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int _system_timeout(const char *cmdstring, int timeout); /*one hundred of a second*/
int system_timeout(const char *cmdstring, int timeout); 

int main(int argc, char **argv)
{
    if(argc != 2)
    {
        printf("usage: %s [command]\n", argv[0]);
    }
    if(0 != system_timeout(argv[1], 50))
    {
        printf("system_timeout error\n");
        return -1;
    }
    printf("system_timeout success\n");
    return 0;
}


int _system_timeout(const char *cmdstring, int timeout)
{
    pid_t pid;
    int status;
    struct sigaction ignore, saveintr, savequit;
    sigset_t chldmask, savemask;

    if(cmdstring == NULL)
        return 1;
    ignore.sa_handler = SIG_IGN;
    sigemptyset(&ignore.sa_mask);
    ignore.sa_flags = 0;
    if(sigaction(SIGINT, &ignore, &saveintr) < 0)
    {
        return -1;
    }
    if(sigaction(SIGQUIT, &ignore, &savequit) < 0)
    {
        return -1;
    }
    sigemptyset(&chldmask);
    sigaddset(&chldmask, SIGCHLD);
    if(sigprocmask(SIG_BLOCK, &chldmask, &savemask) < 0)
    {
        return -1;
    }
    if((pid = fork()) < 0)
    {
        return -1;
    }
    else if(pid == 0)
    {
        sigaction(SIGINT, &saveintr, NULL);
        sigaction(SIGQUIT, &savequit, NULL);
        sigprocmask(SIG_SETMASK, &savemask, NULL);
        execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
        _exit(127);
    }
    else
    {
        usleep(timeout * 10000);
        kill(pid, SIGKILL);
        waitpid(pid, &status, 0);
    }
    if(sigaction(SIGINT, &saveintr, NULL) < 0)
    {
        return -1;
    }
    if(sigaction(SIGQUIT, &savequit, NULL) < 0)
        return -1;
    if(sigprocmask(SIG_SETMASK, &savemask, NULL) < 0)
        return -1;
    return status;
}


int system_timeout(const char *cmdstring, int timeout) 
{
    int ret = 0;
    struct sigaction chldnew, chldold;
    if(cmdstring == NULL)
        return -1;
    bzero(&chldnew, sizeof(struct sigaction));
    bzero(&chldold, sizeof(struct sigaction));
    chldnew.sa_handler = SIG_DFL;
    sigemptyset(&chldnew.sa_mask);
    chldnew.sa_flags = 0;
    if(sigaction(SIGCHLD, &chldnew, &chldold) < 0)
    {
        return -1;
    }
    if((timeout * 10000) < 0)
    {
        return -1;
    }
    else if(timeout == 0)
    {
        ret = system(cmdstring);
    }
    else
    {
        ret = _system_timeout(cmdstring, timeout);
    }
    if(sigaction(SIGCHLD, &chldold, NULL) < 0)
    {
        return -1;
    }
    return ret;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章