【问题标题】:Calling to siglongjmp from SIGVTALRM handler (multithreading with sigaction)从 SIGVTALRM 处理程序调用 siglongjmp(带 sigaction 的多线程)
【发布时间】:2020-08-03 00:56:41
【问题描述】:

您好,我在使用 siglongjmp(多线程)和 sigaction 配置 SIGVTALRM 处理程序时遇到问题。

我已经配置了 sigsetjmp 2 个新线程: 1. env[0] with PC on func f 2. env[1] with PC on func g

我已经为 SIGVTALRM 信号配置了一个处理程序,以便在两个线程之间切换。

我将 itimer_virtual 设置为调用一个名为“switchThreads”的函数,该函数在线程之间切换。

我已经测试了 2 个案例:

  1. 设置定时器并调用无限循环,它只调用一次信号,然后在 siglongjmp 之后停止调用处理程序。

  2. 设置定时器并在它之后调用 f,甚至一次都不调用处理程序。

这是我的代码:

#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();
}

我也知道这 2 个电话:

第一个(只出现一次):

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

第二个(甚至没有发生一次):

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

提前致谢!!

【问题讨论】:

    标签: multithreading signals sigaction


    【解决方案1】:

    我已经设法解决了这个问题,uslepp 停止了线程的执行,因此计时器被配置为 1 秒,并且 2 个函数在它们的循环中使用 usleep,它从未达到 1 秒的运行时间。

    来自沉睡者:

    The usleep() function suspends execution of the calling thread for
           (at least) usec microseconds.  The sleep may be lengthened slightly
           by any system activity or by the time spent processing the call or by
           the granularity of system timers.
    

    【讨论】:

      猜你喜欢
      • 2021-04-26
      • 2019-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多