如何编写测试用例以验证Linux中sem_wait函数返回的EINTR

时间:2018-08-07 11:35:44

标签: c linux semaphore

我刚刚编写了以下例程来处理EINTR错误。 该例程如下所示,

while((s = sem_wait(&w4compl)) == -1)
{
        if (errno == EINTR)
        {
                perror("call interrupted by sig. handler\n");
                continue;
        }
        else
                printf("Other Error Generated\n");
}

所以,在这里我看不到打印的“被信号处理程序中断的呼叫\ n”语句。如何测试它以便打印相同(我该如何执行if(errno == EINTR)的部分)。

2 个答案:

答案 0 :(得分:1)

安装信号处理程序,并导致传递信号(使用alarm()setitimer()timer_create() + timer_settime()),以便传递信号将中断sem_wait()通话。


请考虑以下示例程序:

#define  _POSIX_C_SOURCE  200809L
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <semaphore.h>
#include <stdio.h>
#include <errno.h>

static void dummy_handler(int signum)
{
}

static int install_dummy_handler(int signum)
{
    struct sigaction  act;
    memset(&act, 0, sizeof act);
    sigemptyset(&act.sa_mask);
    act.sa_handler = dummy_handler;
    act.sa_flags = 0;
    return sigaction(signum, &act, NULL);
}

static const char *errname(const int errnum)
{
    switch (errnum) {
    case EINTR:  return "EINTR";
    case EINVAL: return "EINVAL";
    default:     return "(other)";
    }
}

int main(void)
{
    sem_t  s;

    if (install_dummy_handler(SIGALRM) == -1) {
        fprintf(stderr, "Cannot install ARLM signal handler: %s.\n", strerror(errno));
        return EXIT_FAILURE;
    }

    sem_init(&s, 0, 0);

    alarm(1);

    if (sem_wait(&s) == -1) {
        const int  errnum = errno;
        printf("sem_wait() failed with errno == %s (%d; %s).\n",
               errname(errnum), errnum, strerror(errnum));
    } else
        printf("sem_wait() succeeded.\n");

    return EXIT_SUCCESS;
}

main()中,我们为SIGALRM信号安装了一个信号处理程序。信号处理程序函数是否执行任何操作都没有关系,因为信号的传递会导致“慢速”系统调用返回EINTR错误。 (只要安装该处理程序时未使用SA_RESTART标志 。如果您查看act.sa_mask中的install_dummy_handler(),就会发现我们根本没有使用任何标志。在man 2 sigaction手册页中描述了所有标志和sigaction()的用法。)

main()中,我们首先初始化信号量,然后将警报设置一秒钟。实际的挂钟时间过去后,SIGALRM信号会升高。 请注意,尽管SIGALRM对于该示例和类似目的而言是很好的选择,但您可能想要使用POSIX per-process interval timers

接下来,我们只需在信号量上调用sem_wait(),然后检查结果即可。实际上,如果您编译并运行上述 example.c ,例如

gcc -Wall -O2 example.c -lpthread -o example
./example

程序将输出

sem_wait() failed with errno == EINTR (4; Interrupted system call).

一秒钟后。

答案 1 :(得分:0)

如果系统调用被中断,那么在Linux上几乎任何系统调用都可以返回EINTR

来自man page(重点是我):

  

sem_wait()递减(锁定)sem指向的信号量。如果          信号量的值大于零,则递减          继续,函数立即返回。如果信号量          当前的值为零,则调用将阻塞直到其中一个          可以执行减量操作(即信号量值          上升到零以上),或信号处理程序中断通话

要触发这种情况,您应该确保sem_wait系统调用被阻止(正在等待),然后向该线程发送信号(具有处理程序)。

一些伪代码:

sigint_handler:
    return

thread2:
    <Your while loop from the question>

main:
    signal(SIGINT, sigint_handler)  // Setup signal handler

    sem_wait(&w4compl)
    t2 = start_thread(thread2)
    sleep(5)                        // Hack to make sure thread2 is blocked

    pthread_kill(t2, SIGINT)