[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

pthreads, signals, and shared libs



The attached test program shows what appears to be a bug in pthread
signal handling with shared libs, tested on
OpenBSD hana.snafu.org 3.0 HANA#22 i386

OK: Not linked with -pthread

	$ cc main.c
	$ ./a.out
	^Cterminated by signal 2

BAD: linked with -pthread, threads NOT used

	$ cc -pthread main.c    
	$ ./a.out
	^C  (signal ignored)

OK: staticly linked with -pthread, threads NOT used

	$ cc -static -pthread main.c
	$ ./a.out                    
	^Cterminated by signal 2

OK: staticly linked with -pthread, threads used

	$ cc -static -pthread -DTHREAD main.c
	$ ./a.out                                                                  
	^Cterminated by signal 2

Note that it is just the act of linking with -pthread that breaks
the code.  Threads no not have to be used.
Workaround: don't use shared libs with -pthread.

---- main.c ----
#if defined(THREAD)
#include <pthread.h>
#endif

#include <signal.h>

typedef void (*Signal_handler)(int);

struct signal_state {
	int		sig;
	int		signal_pending;
	Signal_handler	top_half;
	struct sigaction bottom_half;
} signal_state[NSIG + 1];

int running;

void
term_sig(int sig)
{
	running = 0;
	printf("terminated by signal %d\n", sig);
}

void
signal_handler(int sig)
{
	if ((sig >= 1) && (sig <= NSIG)) {
		signal_state[sig].signal_pending = 1;
	}
}

int
signal_set(int sig, Signal_handler handler, Signal_handler top_half)
{
	int result;
	struct signal_state *s;

	if ((sig < 1) || (sig > NSIG)) {
		printf("signal_set: sig %d out of range\n", sig);
		exit(1);
	}
	s = &signal_state[sig];
	s->sig = sig;
	s->signal_pending = 0;
	s->top_half = top_half;
	s->bottom_half.sa_handler = handler;
	sigemptyset(&s->bottom_half.sa_mask);
	s->bottom_half.sa_flags = 0;
	result = sigaction(sig, &s->bottom_half, 0);
	if (result == -1) {
		warn("setting signal handler %p", handler);
	}
	return result;
}

void
signal_process(void)
{
	struct signal_state *s;

	for (s = &signal_state[1]; s < &signal_state[NSIG + 1]; s += 1) {
		if (s->sig && s->signal_pending && s->top_half) {
			s->signal_pending = 0;
			(*s->top_half)(s->sig);
		}
	}
}

void *
thread(void *arg)
{
	sigset_t sigs;

	running = 1;

	signal_set(SIGHUP, signal_handler, term_sig);
	signal_set(SIGINT, signal_handler, term_sig);

	sigemptyset(&sigs);
	while (running) {
	    sigsuspend(&sigs);
	    signal_process();
	}
	return 0;
}

int
main(int argc, char *argv[])
{
#if defined(THREAD)
	pthread_t thread_id;

	pthread_create(&thread_id, 0, thread, 0);
	pthread_join(thread_id, 0);
#else
	thread(0);
#endif
	return 0;
}