Вызов siglongjmp из обработчика SIGVTALRM (многопоточность с sigaction) - PullRequest
0 голосов
/ 20 апреля 2020

Здравствуйте! У меня проблема с работой siglongjmp (многопоточность) и настройкой sigaction для обработки обработчика SIGVTALRM.

Я настроил с sigsetjmp 2 новых потока: 1. env [0] с P C on fun c f 2. env [1] с P C on fun c g

Я настроил обработчик для сигнала SIGVTALRM, чтобы переключаться между двумя потоками.

Я установил itimer_virtual для вызова забавного c, называемого "switchThreads", который переключается между потоками.

Я протестировал 2 случая:

  1. Настройка таймер и вызов бесконечного l oop, он вызывает сигнал только один раз, а затем после 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

Заранее спасибо! !

1 Ответ

0 голосов
/ 21 апреля 2020

Мне удалось это исправить, uslepp останавливает выполнение потока, так как таймер был настроен на 1 секунду, и 2 функа использовали usleep в их l oop, он никогда не достигал 1 se c времени работы.

От человека, уснувшего:

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.
...