sigwait дублировал и преобразовывал сигналы в macOS

#c #macos #pthreads

#c #macos #pthreads

Вопрос:

Я вижу несогласованную передачу сигналов между двумя потоками с помощью posix pthread / signaling api.

Вот моя тестовая программа

 #include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

void *thr_fn(void *arg)
{
    int err, signo;
    sigset_t    mask;

   sigemptyset(amp;mask);
   sigaddset(amp;mask,SIGUSR1);
   sigaddset(amp;mask,SIGUSR2);
   sigaddset(amp;mask,SIGABRT);

    printf("Thread Checkern");
    
    while(1) {
        err = sigwait(amp;mask, amp;signo);
        if (err != 0)
        {
            printf("sigwait failed %dn",err);
            exit(1);
        }
        
        switch(signo)
        {
            case SIGUSR1:
                printf("SIGUSR1n");
                break;
            case SIGUSR2:
                printf("SIGUSR2n");
                break;
            case SIGABRT:
                printf("SIGABRTn");
                break;
            default:
                printf("Signal %dn",signo);
                break;
        }
    }
}

int main(void)
{
    int         err;
    pthread_t   tid;
    sigset_t mask;
    
    sigemptyset(amp;mask);
    sigaddset(amp;mask,SIGUSR1);
    sigaddset(amp;mask,SIGUSR2);
    sigaddset(amp;mask,SIGABRT);
    pthread_sigmask(SIG_BLOCK,amp;mask,NULL);
    
    err = pthread_create(amp;tid, NULL, thr_fn, 0);
    if (err != 0)
    {
        printf("can't create thread %d",err);
        exit(1);
    }

    sleep(1);

    for(int x=0;x<5;x  )
    {
        printf("set %dn",x);
        usleep(100000);
        // raise(SIGUSR1);
        pthread_kill(tid, SIGUSR1);
        pthread_kill(tid, SIGUSR2);
        pthread_kill(tid, SIGABRT);
        usleep(500000);
        printf("n");
    }
    
    printf("Donen");
    exit(0);    
}
  

Я ожидаю увидеть 5 групп идентифицированных сигналов, похожих на приведенные ниже:

 set 1
SIGUSR1
SIGUSR2
SIGABRT

  

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

 $ cc -pthread main.c
$ ./a.out
Thread Checker
set 0
SIGUSR1
SIGABRT
SIGUSR2

set 1
SIGUSR2
SIGABRT
SIGUSR2

set 2
SIGUSR1
SIGABRT
SIGUSR2

set 3
SIGUSR1
SIGABRT
SIGUSR2

set 4
SIGUSR1
SIGABRT
SIGUSR2

Done
Program ended with exit code: 0
  

Обратите внимание, что в наборе 1 есть 2 SIGUSR2. Каждый раз, когда я запускаю программу, я часто получаю разное количество сигналов. Использование закомментированного повышения (SIGUSR1) вместо pthread_kill(tid, SIGUSR1) не помогает.

Итак, вопросы в том, что происходит с SIGWAIT? Почему возможно, чтобы сигналы меняли тип или дублировались в очереди сигналов. Почему это не согласованное поведение? Мы видим, что это работает на 100% в Linux, но в WSL это также плохо работает.

Комментарии:

1. Я протестировал это на своем macOS, работающем под управлением Mojave и компилирующемся с clang версии 11.0.0, и я действительно получил сигнал 0 в первом наборе там, я также вижу дублирующийся SIGUSR1, но SIGABRT, похоже, работает довольно стабильно — странно.

2. Интересно, используют ли потоки OS X сигналы SIGUSRn для вещей, подобных старой реализации LinuxThreads?

3. Мы также видели сигнал 0 в первом наборе. Это очень странно, поскольку его нет в списке SIGxxx.

Ответ №1:

Я добавил:

 void dummy(int sig) {
    dprintf(1, "Dummy %dn", sig);
}
  

и:

 signal(SIGUSR1, dummy);
signal(SIGUSR2, dummy);
signal(SIGABRT, dummy);
  

в верхней части main; и это работает так, как ожидалось, и фиктивный никогда не вызывается.
В man sigwait:

Сигналы, указанные set, должны блокироваться, но не игнорироваться, во время вызова sigwait().

обновление: если вы измените это на fork в thr_fn вместо pthread_create , это будет работать без установления фиктивных параметров; что приводит к гипотезе: macos изменяет SIG_DFL при создании потока. Это не противоречит беспорядку, который представляют собой сигналы pthreads . Если вы планируете использовать обе эти парадигмы, возможно, вам захочется нажать паузу….

Комментарии:

1. Я попробую это сделать. Для ясности, регистрация обработчика сигнала гарантирует, что сигнал не игнорируется на странице руководства? Мы используем сигналы и pthreads для написания симуляции RTOS. Это несколько хорошо сочетается с pthreads и сильно отличается от fork.

2. Я смог добавить обработчик сигналов, а затем заблокировать все сигналы. Sigwait по-прежнему иногда выдает странные результаты.

3. Я использовал signal в начале main, как вы показываете, вместо sigaction, и, похоже, он работает правильно.

Ответ №2:

Я предполагаю, что вы запускаете программу в debugger на macOS, когда наблюдаете странное поведение. Попробуйте запустить его непосредственно с терминала без отладчика.

Комментарии:

1. К сожалению, мы протестировали на терминале и увидели неправильное поведение.