On Fri, 20 Jul 2012, Michael Podolsky wrote:
> to my disappointment I found that there is no straightforward solution
> to associate a sigjmp_buf buffer with a particular thread.
I'm not sure if it's a good idea, but I can think of three hacks:
(1)
<
http://gcc.gnu.org/onlinedocs/gcc/Thread_002dLocal.html#Thread_002dLocal>
(2)
<
http://pubs.opengroup.org/onlinepubs/000095399/functions/sigaltstack.html>
<
http://pubs.opengroup.org/onlinepubs/000095399/functions/sigaction.html>
(I'm referencing v3 of the SUS on purpose, because I think it might be
better supported in practice.)
#define _XOPEN_SOURCE 600
#include <signal.h>
#include <stdlib.h>
#include <setjmp.h>
static char unsigned *stacks;
static sigjmp_buf *bufs;
static void
handler(int);
static void
main_setup(size_t num_threads)
{
struct sigaction sa;
stacks = malloc(num_threads * SIGSTKSZ);
bufs = malloc(num_threads * sizeof *bufs);
sa.sa_handler = &handler;
if (-1 == sigemptyset(&sa.sa_mask)) {
abort();
}
sa.sa_flags = SA_ONSTACK;
if (-1 == sigaction(SIGSEGV, &sa, 0)) {
abort();
}
}
static void
thread_setup(unsigned my_id)
{
stack_t stk;
stk.ss_sp = stacks + my_id * SIGSTKSZ;
stk.ss_size = SIGSTKSZ;
stk.ss_flags = 0;
if (-1 == sigaltstack(&stk, 0)) {
abort();
}
}
static void
handler(int signo)
{
stack_t stk;
size_t my_id;
if (-1 == sigaltstack(0, &stk) || 0 == (stk.ss_flags & SS_ONSTACK)) {
abort();
}
my_id = ((char unsigned *)stk.ss_sp - stacks) / SIGSTKSZ;
siglongjmp(bufs[my_id], 1);
abort();
}
(sigaltstack() is not listed as async signal safe, but I'm not sure how
SS_ONSTACK can make sense otherwise.)
(3)
#define _XOPEN_SOURCE 600
#include <signal.h>
#include <stdlib.h>
#include <setjmp.h>
#include <pthread.h>
#include <ucontext.h>
static void **sps;
static sigjmp_buf *bufs;
static pthread_barrier_t init;
static void
handler(int, siginfo_t *, void *);
static void
main_setup(size_t num_threads)
{
struct sigaction sa;
sps = malloc((num_threads + 1u) * sizeof *sps);
sps[num_threads] = 0;
bufs = malloc(num_threads * sizeof *bufs);
if (-1 == sigemptyset(&sa.sa_mask)) {
abort();
}
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
if (-1 == sigaction(SIGSEGV, &sa, 0)) {
abort();
}
if (-1 == pthread_barrier_init(&init, 0, num_threads)) {
abort();
}
}
static void
thread_setup(unsigned my_id)
{
ucontext_t context;
getcontext(&context);
sps[my_id] = context.uc_stack.ss_sp;
pthread_barrier_wait(&init);
}
static void
handler(int signo, siginfo_t *info, void *context)
{
void *my_sp;
size_t my_id;
my_sp = ((ucontext_t *)context)->uc_stack.ss_sp;
for (my_id = 0; 0 != sps[my_id]; ++my_id) {
if (sps[my_id] == my_sp) {
siglongjmp(bufs[my_id], 1);
}
}
abort();
}
Laszlo