Bug 31661

Summary: pthread_kill signal handler doesn't get sigcontext or ucontext
Product: Base System Reporter: Nicholas Barnes <nb>
Component: binAssignee: freebsd-threads (Nobody) <threads>
Status: Closed FIXED    
Severity: Affects Only Me CC: mps-staff
Priority: Normal    
Version: 4.4-STABLE   
Hardware: Any   
OS: Any   

Description Nicholas Barnes 2001-10-31 12:30:06 UTC
The signal handler for a signal caused by pthread_kill only receives a
single useful argument: the signal.  Man sigaction says it should get
either code + sigcontext or info + ucontext (depending on whether
SA_SIGINFO is set).  But in fact these subsequent arguments always get
0 (or NULL).

This means that I can't use pthread_kill to suspend a thread and get
its context; required for some kinds of garbage collection.

Fix: 

Not known.  May be related to the fact that _thread_sig_send()
(lib/libc_r/uthread/uthread_sig.c) passes 0 as the has_args argument
to thread_sig_add(), under certain circumstances.
How-To-Repeat: 
/* Test program to show that per-thread signals are not delivered with
 * useful code, sigcontext, siginfo, or ucontext.
 * FreeBSD 4.4-STABLE, 2001-10-31.
 * Nick Barnes, 2001-10-31.
 */

#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

/* variables to record the arguments passed to signal handlers */
static int ANSIHandled = 0;
static int ANSISignal = 0;
static pthread_t ANSIPthread = NULL;

static int BSDHandled = 0;
static int BSDSignal = 0;
static int BSDCode = 0;
static struct sigcontext *BSDSigcontext = NULL;
static pthread_t BSDPthread = NULL;

static int PosixHandled = 0;
static int PosixSignal = 0;
static siginfo_t *PosixInfo = NULL;
static void *PosixContext = NULL;
static pthread_t PosixPthread = NULL;

/* a mutex for all the threads to wait on */
static pthread_mutex_t mutex;

/* three possible signal handlers.  See man sigaction. */


/* ANSI signal handler prototype */
static void ANSIHandler(int sig)
{
    ANSIHandled = 1;
    ANSISignal = sig;
    ANSIPthread = pthread_self();
}

/* BSD signal handler prototype */
static void BSDHandler(int sig, int code, struct sigcontext *scp)
{
    BSDHandled = 1;
    BSDSignal = sig;
    BSDCode = code;
    BSDSigcontext = scp;
    BSDPthread = pthread_self();
}

/* Posix signal handler prototype */
static void PosixHandler(int sig, siginfo_t *info, void *context)
{
    PosixHandled = 1;
    PosixSignal = sig;
    PosixInfo = info;
    PosixContext = context;
    PosixPthread = pthread_self();
}

/* A function for a thread to run. */
void *ThreadStart(void *arg)
{
    const char *name = (const char *)arg;
    pthread_t self = pthread_self();
    printf("%s is alive: 0x%08x\n", name, self);
    /* try to lock the mutex.  This will sleep for ever */
    pthread_mutex_lock(&mutex);
}

#define ANSISIG  SIGUSR1
#define BSDSIG   SIGUSR2
#define PosixSIG SIGXFSZ


int main(void)
{
    struct sigaction ANSISigaction, BSDSigaction, PosixSigaction;
    pthread_t ANSIThread, BSDThread, PosixThread;

    ANSISigaction.sa_handler = ANSIHandler;
    ANSISigaction.sa_flags = 0;
    sigaction(ANSISIG, &ANSISigaction, NULL);

    BSDSigaction.sa_handler = BSDHandler;
    BSDSigaction.sa_flags = 0;
    sigaction(BSDSIG, &BSDSigaction, NULL);

    PosixSigaction.sa_sigaction = PosixHandler;
    PosixSigaction.sa_flags = SA_SIGINFO;
    sigaction(PosixSIG, &PosixSigaction, NULL);

    pthread_mutex_init(&mutex, NULL);
    pthread_mutex_lock(&mutex);

    pthread_create(&ANSIThread,  NULL, ThreadStart, "ANSI");
    pthread_create(&BSDThread,   NULL, ThreadStart, "BSD");
    pthread_create(&PosixThread, NULL, ThreadStart, "Posix");
    printf("ANSI Thread  0x%08x\n", ANSIThread);
    printf("BSD Thread   0x%08x\n", BSDThread);
    printf("Posix Thread 0x%08x\n", PosixThread);
    /* wait for the threads to be alive */
    printf("waiting for the threads to be alive\n");
    /* I know I could use a pthreads mechanism for this,
     * but I wanted to keep it simple. */
    sleep(5);

    pthread_kill(ANSIThread, ANSISIG);
    pthread_kill(BSDThread, BSDSIG);
    pthread_kill(PosixThread, PosixSIG);
    /* wait for the signals to be delivered. */
    printf("waiting for the signals to be delivered\n");
    /* I know I could use a pthreads mechanism for this,
     * but I wanted to keep it simple. */
    sleep(5);

    printf("ANSI:  Handled %d signal %d pthread 0x%08x\n",
           ANSIHandled, ANSISignal, ANSIPthread);
    printf("BSD:   Handled %d signal %d pthread 0x%08x code %d sigcontext 0x%08x\n",
           BSDHandled, BSDSignal, BSDPthread, BSDCode, BSDSigcontext);
    printf("Posix: Handled %d signal %d pthread 0x%08x info 0x%08x context 0x%08x\n",
           PosixHandled, PosixSignal, PosixPthread, PosixInfo, PosixContext);
    return 0;
}
Comment 1 Nicholas Barnes 2001-11-01 12:55:54 UTC
I forgot to provide the results of running the test program.  Here
they are.  The bug is demonstrated by the last two lines of output:
the code, sigcontext, info, and context variables are all zero.

$ cc -pthread test.c
test.c: In function `main':
test.c:87: warning: assignment from incompatible pointer type
$ ./a.out
ANSI Thread  0x0804c400
BSD Thread   0x0804cc00
Posix Thread 0x0805f000
waiting for the threads to be alive
ANSI is alive: 0x0804c400
BSD is alive: 0x0804cc00
Posix is alive: 0x0805f000
waiting for the signals to be delivered
ANSI:  Handled 1 signal 30 pthread 0x0804c400
BSD:   Handled 1 signal 31 pthread 0x0804cc00 code 0 sigcontext 0x00000000
Posix: Handled 1 signal 25 pthread 0x0805f000 info 0x00000000 context 0x00000000
$
Comment 2 Jason Evans freebsd_committer freebsd_triage 2001-12-17 19:36:14 UTC
Responsible Changed
From-To: freebsd-bugs->jasone

I'll take a look at this.
Comment 3 Jason Evans freebsd_committer freebsd_triage 2002-05-11 23:22:53 UTC
Responsible Changed
From-To: jasone->freebsd-bugs
Comment 4 Kris Kennaway freebsd_committer freebsd_triage 2003-07-13 02:36:45 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-threads

Assign to threads mailing list
Comment 5 Craig Rodrigues 2004-02-02 21:39:30 UTC
Hi,

I just tried your test program on FreeBSD-CURRENT.

When linked with -lc_r, the output is:

NSI Thread  0x0804c400
BSD Thread   0x0804cc00
Posix Thread 0x0805f000
waiting for the threads to be alive
ANSI is alive: 0x0804c400
BSD is alive: 0x0804cc00
Posix is alive: 0x0805f000
waiting for the signals to be delivered
ANSI:  Handled 1 signal 30 pthread 0x0804c400
BSD:   Handled 1 signal 31 pthread 0x0804cc00 code 0 sigcontext 0x00000000
Posix: Handled 1 signal 25 pthread 0x0805f000 info 0x00000000 context 0x00000000



When linked with -lpthread, the output is:

ANSI Thread  0x08053400
BSD Thread   0x08053600
Posix Thread 0x08053800
waiting for the threads to be alive
ANSI is alive: 0x08053400
BSD is alive: 0x08053600
Posix is alive: 0x08053800
waiting for the signals to be delivered
ANSI:  Handled 1 signal 30 pthread 0x08053400
BSD:   Handled 1 signal 31 pthread 0x08053600 code 0 sigcontext 0xbfaddbe8
Posix: Handled 1 signal 25 pthread 0x08053800 info 0xbfacdb58 context 0xbfacdbe8


You mentioned that the bug is demonstrated by the fact
that sigcontext and context are 0 in the last two lines of the output.

This problem does not seem to exist for the new pthread library.

-- 
Craig Rodrigues        
rodrigc@crodrigues.org
Comment 6 Nicholas Barnes 2004-02-02 21:50:13 UTC
At 2004-02-02 21:39:30+0000, Craig Rodrigues writes:

> This problem does not seem to exist for the new pthread library.

Great, thanks!  I must try out -CURRENT.

The underlying functionality is essential for some applications
(basically anything which needs to pause other threads in order to
introspect on their stacks, e.g. for garbage collection).

Nick B
Comment 7 Daniel Eischen freebsd_committer freebsd_triage 2004-02-04 15:47:36 UTC
State Changed
From-To: open->closed

This is written against libc_r's implementation of pthread_kill; 
libpthread does provide full signal handler arguments to pthread_kill. 
Still it iw worth noting that trying to do anything sane with 
a context from a pthread_kill() is probably not what you want 
especially for scope process threads.  pthread_kill() is a 
simulated interrupt and the threads interrupted context is generated 
by the threads library -- it is not like a real signal interrupted 
the thread while it was running.