从信号处理程序返回

5

我的信号处理函数不是没有以正确的方式离开吗?它似乎不能正常返回程序。相反,它进入了循环,在那里它应该等待用户输入时,跳过并将"用户输入"的长度读取为-1,并出现错误。(在代码中更容易理解)

void handle_SIGINT() {

    int k = recent;
    int count = 0;
    int stop;

    if (stringSize >= 10) {
        stop = 10;
    }
    else {
        stop = p;
    }

    printf("\nCommand History:\n");

    for (count = 0; count < stop; count++) {

        if (k < 0) {
            k += 10;
        }
        printf("%s", string[abs(k)]);
        k -= 1;

    }

}



void setup(char inputBuffer[], char *args[],int *background)
{
    //char inputBuffer[MAX_LINE];
    int length, /* # of characters in the command line */
    i,      /* loop index for accessing inputBuffer array */
    start,  /* index where beginning of next command parameter is */
    ct;     /* index of where to place the next parameter into args[] */
    int add = 1;
    ct = 0;

    /* read what the user enters on the command line */
    length = read(STDIN_FILENO, inputBuffer, MAX_LINE);  


        printf("%i",length);
    start = -1;
    if (length == 0)
        exit(0);            /* ^d was entered, end of user command stream */
    if (length < 0){
        perror("error reading the commanddddddddd");
        exit(-1);           /* terminate with error code of -1 */
    }
}



int main(void)
{
    char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
    int background;             /* equals 1 if a command is followed by '&' */
    char *args[MAX_LINE/2+1];/* command line (of 80) has max of 40 arguments */
    FILE *inFile = fopen("pateljay.history", "r");



    if (inFile != NULL) {
        int count = 0;
        char line[MAX_LINE];
        while (fgets(line,sizeof line, inFile) != NULL) {
            string[count] = strdup(line);
            //string[count][strlen(line)] = '\n';
            //string[count][strlen(line) + 1] = '\0';
            printf("%s", string[count]);
            count++;
            stringSize++;
        }


            p = count % 10;
            recent = abs(p - 1);

    }   

    fclose(inFile); 

    /* set up the signal handler */
    struct sigaction handler;
    handler.sa_handler = handle_SIGINT;
    sigaction(SIGINT, &handler, NULL);

    while (1) {/* Program terminates normally inside setup */


        background = 0;
        printf("COMMAND->");

        fflush(0);

        setup(inputBuffer, args, &background);/* get next command */
    }
}

当输入ctrl+c时,应该捕获信号并处理它。一旦返回到主函数,它将进入设置并完全跳过读取函数,并将长度设为-1。这反过来会导致程序出错。我认为handle_SIGINT内部的代码现在是无关紧要的。有人知道为什么它会跳过设置中的读取函数吗?


6
在信号处理程序中不能使用printf()函数。 - wildplasser
2
关于printf问题,当在信号处理程序中使用时,请参考此问题和答案:https://dev59.com/6EzSa4cB1Zd3GeqPoJ50#2461602 - Macmade
3
@Tom:因为它不是可重入的。(printf可能会调用malloc来获取缓冲区空间,而且由于它是从信号处理程序中调用的,这可能会干扰malloc。也许当被中断时stdio的内部处理也会变得混乱) - wildplasser
1
printf 从信号处理程序中移除是一个相当棘手的问题。请参考 http://osiris.978.org/~alex/safesignalhandling.html 获取一些解决方案。 - rob mayoff
我应该只在信号处理程序中更改布尔状态,并在主函数外部使用printf吗?那样会更好吗? - jaiesh
显示剩余7条评论
2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
8

read 是阻塞的,等待输入。当 SIGINT 到达时,内核会调用你的信号处理程序。当你的信号处理程序返回时,内核会让 read 返回 -1,并将 errno 设置为 EINTR。你需要检查这种情况并通过再次调用 read 来处理它:

   do {
        length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
   } while (length == -1 && errno == EINTR);

errno是由内核为所有程序定义的吗? - jaiesh
1
顺便说一下,我从不使用这种解决方案,除非在玩具程序中,因为它无法解决从信号处理程序调用 printf 的问题,这是被禁止的。在一个严肃的程序中,我会使用自管道技巧。 - rob mayoff
你需要 #include <errno.h> 来获取 errno 的正确定义。 - rob mayoff
好的,非常感谢,特别是关于信号处理程序的额外信息。我查了一下self-pipe技巧,可能会尝试一下。还找到了一些关于pselect的信息。不确定select实际上是做什么的,我是否应该在while循环中包含它以使信号处理程序返回那里? - jaiesh
我建议使用poll而不是select,因为poll的接口更简单。对于任何一种方法,这个页面可能会很有用:http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/rzab6/example.htm - rob mayoff
@jaiesh 它在 libc 中被定义。 - Vad

1
信号处理程序应该接受一个 int 参数:
void handle_sigint(int signum) {}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,