Bug#159899: libc6: sem_wait is not interrupted by signals, as required by SuS
Package: libc6
Version: 2.2.5-14
Severity: normal
Tags: upstream
The Single Unix standard requires sem_wait() to be
interrupted by a signal delivered to the process - see
http://www.opengroup.org/onlinepubs/007908799/xsh/sem_wait.html for
details. The glibc implementation of sem_wait(), however, continues
to wait on the semaphore after the signal is delivered.
To demonstrate this, I have appended a test program. Compile
with -pthread and run it; it will block forever, and be unresponsive
to ^C (^\ will kill it). On a Solaris machine, by contrast, it exits
successfully, printing nothing, after a short delay (due to the
nanosleep() call in child_thread).
Code inspection suggests this is still a bug in the latest glibc CVS.
-- System Information:
Debian Release: testing/unstable
Architecture: i386
Kernel: Linux egil 2.4.19 #1 Thu Aug 15 11:07:52 PDT 2002 i686
Locale: LANG=en_US, LC_CTYPE=en_US
-- test program:
#include <sys/types.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static pid_t me;
static sem_t sema;
static volatile sig_atomic_t sigint_caught = 0;
static void *
child_thread(void *unused)
{
sigset_t all;
struct timespec ts;
/* Block all signals in this thread. */
sigfillset(&all);
sigprocmask(SIG_SETMASK, &all, 0);
/* Wait a moment to be sure the main thread is blocked on the
semaphore. */
ts.tv_sec = 1;
ts.tv_nsec = 0;
nanosleep(&ts, 0);
/* Now feed the main thread a signal. This should interrupt
execution of sem_wait(). */
kill(me, SIGINT);
return 0;
}
static void
sigint_handler(int unused)
{
sigint_caught = 1;
}
int
main(void)
{
sigset_t none;
pthread_t child;
struct sigaction sa;
int status;
int semv;
/* Initialize... */
me = getpid();
sem_init(&sema, 0, 0); /* semaphore starts out locked */
sigemptyset(&none);
sigprocmask(SIG_SETMASK, &none, 0);
sa.sa_handler = sigint_handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, 0);
/* Spawn child thread. */
pthread_create(&child, 0, child_thread, 0);
/* Block on semaphore. This should be interrupted by the
child sending us a signal. */
status = sem_wait(&sema);
/* status should be -1, errno should be EINTR, sigint_caught
should be 1, and the semaphore value should still be zero. */
if(status != -1)
printf("status = %d != -1\n", status);
if(errno != EINTR)
printf("errno = %s != EINTR\n", strerror(errno));
if(sigint_caught != 1)
printf("sigint_caught = %d != 1\n", sigint_caught);
sem_getvalue (&sema, &semv);
if(semv != 0)
printf("semv = %d != 0\n", semv);
/* cleanup */
pthread_join(child, 0);
sem_destroy(&sema);
return 0;
}
Reply to: