简体   繁体   中英

How to write a test case to verify EINTR returned by sem_wait function in linux

I have just written the below routine to handle the EINTR error. The routine is given below,

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

SO, here i am not able to see the print "call interrupted by sig. handler\\n" statement. How can test this so that it will print the same(How can i execute the part of if (errno == EINTR)).

Install a signal handler, and cause a signal to be delivered (using alarm() , setitimer() , or timer_create() + timer_settime() ), so that the delivery of the signal will interrupt the sem_wait() call.


Consider this example program:

#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;
}

In main() , we install a signal handler for the SIGALRM signal. It does not matter if the signal handler function does anything at all, because it is the delivery of the signal that causes "slow" syscalls to return with EINTR error. (As long as the SA_RESTART flag was not used when that handler was installed. If you look at act.sa_mask in install_dummy_handler() , you'll see we used no flags at all. All the flags and sigaction() usage are described in the man 2 sigaction man page.)

In main() , we first initialize our semaphore, then set an alarm for one second. When the real, wall-clock time has elapsed, the SIGALRM signal is raised. Do note that although SIGALRM is just fine for this example and similar purposes, you'll probably want to use POSIX per-process interval timers instead.

Next, we simply call sem_wait() on the semaphore, and examine the result. In practice, if you compile and run the above example.c using eg

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

the program will output

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

after one second.

Just about any system call on Linux can return EINTR if the system call is interrupted.

From the man page (emphasis mine):

sem_wait() decrements (locks) the semaphore pointed to by sem . If the semaphore's value is greater than zero, then the decrement proceeds, and the function returns, immediately. If the semaphore currently has the value zero, then the call blocks until either it becomes possible to perform the decrement (ie, the semaphore value rises above zero), or a signal handler interrupts the call .

To trigger this case, you should make sure that the sem_wait system call is blocked (waiting), and then send a signal (which has a handler) to the thread.

Some psuedo-code:

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)

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