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 e.g.
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.