Hello I have an issue to work with siglongjmp (multi threading) and sigaction configuring SIGVTALRM handler.
I've configured with sigsetjmp 2 new threads: 1. env[0] with PC on func f 2. env[1] with PC on func g
I've configured an handler to the SIGVTALRM signal, to switch between the 2 threads.
I set itimer_virtual to call to a func called "switchThreads" that switch between the threads.
I've tested 2 cases:
Setting the timer and calling to infinite loop, It's calling to the signal only once and then after siglongjmp it stops calling the handler.
Setting the timer and calling after it to f, not calling even once to the handler.
Here is my code:
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#define SECOND 1000000
#define STACK_SIZE 4096
char stack1[STACK_SIZE];
char stack2[STACK_SIZE];
sigjmp_buf env[2];
#ifdef __x86_64__
/* code for 64 bit Intel arch */
typedef unsigned long address_t;
#define JB_SP 6
#define JB_PC 7
/* A translation is required when using an address of a variable.
Use this as a black box in your code. */
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%fs:0x30,%0\n"
"rol $0x11,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
#else
/* code for 32 bit Intel arch */
typedef unsigned int address_t;
#define JB_SP 4
#define JB_PC 5
/* A translation is required when using an address of a variable.
Use this as a black box in your code. */
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%gs:0x18,%0\n"
"rol $0x9,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
#endif
static struct sigaction sa;
static struct itimerval timer;
static int currentThread = 0;
static void switchThreads(int sig)
{
int ret_val = sigsetjmp(env[currentThread], 1);
printf("SWITCH: ret_val=%d\n", ret_val);
if (ret_val == 1)
{
return;
}
currentThread = 1 - currentThread;
if (setitimer(ITIMER_VIRTUAL, &timer, NULL))
{
printf("setitimer error.");
}
siglongjmp(env[currentThread], 1);
}
void f(void)
{
int i = 0;
while (1)
{
++i;
printf("in f (%d)\n", i);
usleep(SECOND);
}
}
void g(void)
{
int i = 0;
while (1)
{
++i;
printf("in g (%d)\n", i);
usleep(SECOND);
}
}
void setup(void)
{
address_t sp, pc;
sp = (address_t) stack1 + STACK_SIZE - sizeof(address_t);
pc = (address_t) f;
sigsetjmp(env[0], 1);
(env[0]->__jmpbuf)[JB_SP] = translate_address(sp);
(env[0]->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&env[0]->__saved_mask);
sp = (address_t) stack2 + STACK_SIZE - sizeof(address_t);
pc = (address_t) g;
sigsetjmp(env[1], 1);
(env[1]->__jmpbuf)[JB_SP] = translate_address(sp);
(env[1]->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&env[1]->__saved_mask);
}
int main(void)
{
printf("Starting...");
// Install timer_handler as the signal handler for SIGVTALRM.
sa.sa_handler = &switchThreads;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGVTALRM, &sa, NULL) < 0)
{
printf("sigaction error.");
}
// Configure the timer to expire after 1 sec... */
timer.it_value.tv_sec = 3;
timer.it_value.tv_usec = 0;
// configure the timer to expire every 1 sec after that.
timer.it_interval.tv_sec = 1;
timer.it_interval.tv_usec = 0;
// Start a virtual timer. It counts down whenever this process is executing.
if (setitimer(ITIMER_VIRTUAL, &timer, NULL))
{
printf("setitimer error.");
}
setup();
// for(;;){}
f();
}
I've also the strace of the 2 calls:
The first (occur only once):
rt_sigaction(SIGVTALRM, {sa_handler=0x563ff48db82d, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f22c0f72f20}, NULL, 8) = 0
setitimer(ITIMER_VIRTUAL, {it_interval={tv_sec=1, tv_usec=0}, it_value={tv_sec=3, tv_usec=0}}, NULL) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
--- SIGVTALRM {si_signo=SIGVTALRM, si_code=SI_KERNEL} ---
rt_sigprocmask(SIG_BLOCK, NULL, [VTALRM], 8) = 0
write(1, "Starting...SWITCH: ret_val=0\n", 29Starting...SWITCH: ret_val=0
) = 29
setitimer(ITIMER_VIRTUAL, {it_interval={tv_sec=1, tv_usec=0}, it_value={tv_sec=3, tv_usec=0}}, NULL) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
write(1, "in g (1)\n", 9in g (1)
) = 9
nanosleep({tv_sec=1, tv_nsec=0}, NULL) = 0
write(1, "in g (2)\n", 9in g (2)
) = 9
nanosleep({tv_sec=1, tv_nsec=0}, NULL) = 0
write(1, "in g (3)\n", 9in g (3)
) = 9
The Second (not occuring even once):
rt_sigaction(SIGVTALRM, {sa_handler=0x55dc7274e82d, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe6e3768f20}, NULL, 8) = 0
setitimer(ITIMER_VIRTUAL, {it_interval={tv_sec=1, tv_usec=0}, it_value={tv_sec=3, tv_usec=0}}, NULL) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
write(1, "Starting...in f (1)\n", 20Starting...in f (1)
) = 20
nanosleep({tv_sec=1, tv_nsec=0}, NULL) = 0
write(1, "in f (2)\n", 9in f (2)
) = 9
nanosleep({tv_sec=1, tv_nsec=0}, NULL) = 0
write(1, "in f (3)\n", 9in f (3)
) = 9
nanosleep({tv_sec=1, tv_nsec=0}, NULL) = 0
write(1, "in f (4)\n", 9in f (4)
) = 9
nanosleep({tv_sec=1, tv_nsec=0}, NULL) = 0
write(1, "in f (5)\n", 9in f (5)
) = 9
Thanks in advance!!