Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 11 Jun 2004 01:55:14 -0700
From:      Sean McNeil <sean@mcneil.com>
To:        Daniel Eischen <eischen@vigrid.com>
Cc:        freebsd-amd64@freebsd.org
Subject:   Re: signal handler priority issue
Message-ID:  <1086944114.76446.5.camel@server.mcneil.com>
In-Reply-To: <Pine.GSO.4.10.10406110432370.12394-100000@pcnet5.pcnet.com>
References:  <Pine.GSO.4.10.10406110432370.12394-100000@pcnet5.pcnet.com>

next in thread | previous in thread | raw e-mail | index | archive | help
(I've cc'd the amd64 list so here is some background)

I'm experiencing some odd behavior with signals and threads.  Daniel has
managed to isolate it to an example program that works. Except....

OK, so maybe this is an optimization bug.  The following works fine with
no optimization, but with -O or -O2 it fails on an amd64.  Can someone
test with various optimizations on i386?

Compiled with

cc -o test_sr test_sr.c -pthread
works

cc -O -o test_sr test_sr.c -pthread
or
cc -O2 -o test_sr test_sr.c -pthread
hangs

/*
 * test_sr.c
 *
 * Demonstrate use of signals & semaphores for suspending and
 * resuming threads.
 */
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
#include <unistd.h>

#ifndef NUM_THREADS
#define NUM_THREADS     5
#endif

static sem_t            semaphore;
static int              done = 0;
static pthread_t        tids[NUM_THREADS];

static void
errno_abort(char *msg)
{
        printf("%s, errno %d\n", msg, errno);
        abort();
}

static void
err_abort(int status, char *msg)
{
        printf("%s, status %d\n", msg, status);
        abort();
}

static void
sighandler1(int sig, siginfo_t *info, ucontext_t *ucp)
{
        sigset_t mask;
	int i;
	pthread_t self = pthread_self();

	for (i=0; i<NUM_THREADS && self != tids[i]; i++);

	printf("Thread %d pausing.\n", i);
	sem_post(&semaphore);

	sigfillset(&mask);
	sigdelset(&mask, SIGUSR2);
	sigsuspend(&mask);
	printf("Thread %d successfully resumed.\n", i);
}

static void
sighandler2(int sig, siginfo_t *info, ucontext_t *ucp)
{
	int i;
	pthread_t self = pthread_self();

	for (i=0; i<NUM_THREADS && self != tids[i]; i++);

	printf("Thread %d got resume signal.\n", i);
}

/*
 * Thread start routine to wait on a semaphore.
 */
static void *
worker(void *arg)
{
        int num = (int)arg;
        int x;

        num = (int)arg;
        x = num * 10;

        printf ("Thread %d starting.\n", num);
        while (!done) {
                x = x + 1;
                x = x - 1;
        }
        printf("Thread %d stopping.\n", num);

        return (NULL);
}

static void
pause_threads(void)
{
        int i;

        printf("Master: pausing all threads.\n");
        for (i = 0; i < NUM_THREADS; i++) {
                pthread_kill(tids[i], SIGUSR1);
        }
        for (i = 0; i < NUM_THREADS; i++) {
                if (sem_wait(&semaphore) == -1)
                        errno_abort("Wait on semaphore");
        }
}

static void
resume_threads(void)
{
        int i;

        printf("Master: resuming all threads.\n");
        for (i = 0; i < NUM_THREADS; i++) {
                pthread_kill(tids[i], SIGUSR2);
        }
}

static void *
pause_resume(void *arg)
{
	int i;

        for (i = 0; i < 5; i++) {
                pause_threads();
                resume_threads();
        }

	return NULL;
}

int
main(int argc, char *argv[])
{
	pthread_t prid;
        struct sigaction act;
        int status;
        int i;

        if (sem_init (&semaphore, 0, 0) == -1)
                errno_abort ("Init semaphore");

        /* Mask all signals while in the signal handler. */
        sigfillset(&act.sa_mask);
        act.sa_flags = SA_RESTART;

        act.sa_handler = sighandler1;
        sigaction(SIGUSR1, &act, NULL);

        act.sa_handler = sighandler2;
        sigaction(SIGUSR2, &act, NULL);

        /*
         * Create some worker threads.
         */
        for (i = 0; i < NUM_THREADS; i++) {
                status = pthread_create(&tids[i], NULL, worker, (void
*)i);
                if (status != 0)
                        err_abort (status, "Create thread");
        }

	pthread_create (&prid, NULL, pause_resume, NULL);
	pthread_join(prid, NULL);

        for (i = 0; i < 5; i++) {
                pause_threads();
                resume_threads();
        }

        done = 1;

        /*
         * Wait for all threads to complete.
         */
        for (i = 0; i < NUM_THREADS; i++) {
                status = pthread_join(tids[i], NULL);
                if (status != 0)
                        err_abort(status, "Join thread");
        }
        return (0);
}




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1086944114.76446.5.camel>