LINUX.ORG.RU

Обработка сигналов в линуксе

 , , ,


0

2

Не понимаю, в этом коде все работает нормально, как и должно быть, таймер не завершает работу после первой секунды.

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>

static int count = 0;

struct itimerval timer;

int in = 1;

void sighandler(int sig)
{
    if (sig == SIGALRM)
    {
        count++;
        printf("%d\n", count);

        if (count % 3 == 0)
        {
            timer.it_interval.tv_sec = 0;
            timer.it_value.tv_sec = 0;
            setitimer(ITIMER_REAL, &timer, NULL);
            in = 1;
        }
    }
}
int main()
{
    signal(SIGALRM, sighandler);

    char ch = '0';
    while (1)
    {
        if (in == 1)
        {
            printf("input> ");
            scanf("%c", &ch);
            switch (ch)
            {
                case 's':
                {
                    timer.it_interval.tv_sec = 1;
                    timer.it_value.tv_sec = 1;
                    setitimer(ITIMER_REAL, &timer, NULL);
                    in = 0;
                    break;
                }
                default: break;
            }
        }   
    }
    
    return 0;
}

В другом же коде (не могу его показать), где сама структура идентична этому коду, таймер завершает работу после первого достижения нуля значением it_value. И при этом программа завершается с выводом в терминал «Сигнал таймера», хотя цикл while (1) не должен допускать этого... Вторые сутки бьюсь уже. !!!ЕДИНСТВЕННОЕ!!! что отличает этот код от моего - терминал работает в неканоническом режиме. Но, по идее, это не должно влиять на работу обработчика сигнала. В чем может быть проблема?



Последнее исправление: kennydzzze (всего исправлений: 1)

Ответ на: комментарий от post-factum

Я не понимаю, как можно сравнивать работы этих двух функций? Ну загуглил я про это, ну увидел решение на stack overflow, которым вы, видимо, и воспользовались. Но все это касается работы другой функции! Меня же интересует то, почему код в шапке темы работает правильно, а аналогичный ему реальный код, использующий все то-же самое НЕ работает. Вы видели этот код, вам должен быть понятен мой случай.

kennydzzze
() автор топика
Ответ на: комментарий от kennydzzze

Твой случай в том, что код разный. И он по-разному работает. Ты видишь, в каком месте приходит KILL? Что перед этим происходит? Что происходит в том же месте, но если есть SA_RESTART? И есть ли такое же место в том коде, который ты привёл в шапке темы?

post-factum ★★★★★
()
Ответ на: комментарий от post-factum

Сейчас почитал про функцию sigaction(). Есть мнение, что лучше использовать не SA_RESTART, а SA_NODEFER. Что думаете? vodz, Вас тоже касается.

kennydzzze
() автор топика
Ответ на: комментарий от kennydzzze

Хотя... В будущем же будет не один сигнал. Как будет вести себя эта функция на сигналах, отличных от SIGALRM?

kennydzzze
() автор топика
Ответ на: комментарий от kennydzzze

А вы точно что-то читали? SA_NODEFER эмулирует старые юниксы, когда во время обработки сигнала можно было послать ещё раз и он примется снова, то есть обработчик прервётся в произвольном месте и вызовется рекурсивно. Вам это точно надо? То что я думаю изложено в том числе и в https://groups.google.com/forum/embed/#!topic/fido7.ru.unix.prog/W75J2GayIxg (там были мои несколько патчей к тексту).

vodz ★★★★★
()
Ответ на: комментарий от post-factum

Как говорил vodz: «SA_RESTART позволяет перезапустить любой сискол, имеющий код возврата EINTR». А SA_NODEFER перезапускает только тот сигнал, который я обрабатываю в настоящем времени.

kennydzzze
() автор топика
Ответ на: комментарий от vodz

Если разблокировать в моей программе ввод с клавиатуры и во время таймера подавать тот же сигнал с флагом SA_NODEFER, то работа таймера на рекурсию не похожа. Таймер при каждом новом сигнале начинает работу сначала и до конца, при этом не возвращаясь к той точке прерывания предыдущего сигнала.

kennydzzze
() автор топика
Ответ на: комментарий от kennydzzze

Вы с терминологией разберитесь, читать не возможно. Таймер не в вашей программе работает, а в ядре, в ваше программе работает обработчик и установщик таймера. Сигнал ни с каким флагом не посылается. Чего куда разблокировать вообще одно только вам понятная отсебятина.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Сигнал после отработки таймера посылается в функцию sigaction(), которая этот сигнал принимает и запускает обработчик. А то, как этот сигнал будет обрабатываться, зависит от значения флага sa_flags. Что не так?

kennydzzze
() автор топика
Ответ на: комментарий от post-factum

Цитата из документа, который кидал vodz:

Hа время вызова обработчика текущий сигнал блокируется, если не установлен флаг SA_NODEFER (то есть, сигнал добавляется к маске, описанной в sa_mask). Это необходимо, чтобы избежать зацикливания обработчика.

Т.е. если я этот флаг не устанавливаю, то сигнал, полученный впервые от таймера передастся в обработчик один раз? А если этот флаг установить, то... Я уже сломал себе голову.

kennydzzze
() автор топика
Ответ на: комментарий от kennydzzze

Да нет же.

По умолчанию на время выполнения обработчика сигнал блокируется. Пока обработчик работает, сигнал его не прервёт.

Если установить флаг, то сигнал может прийти во время работы обработчика, прервать обработчик и запустить его снова. Это разве то, что ты хочешь?

post-factum ★★★★★
()
Ответ на: комментарий от post-factum

Как сигнал вообще может прийти во время работы обработчика? Сигнал же приходит, запускает обработчик, обработчик выполняет действия, все. Следующий обработчик запустится только при следующем сигнале. Т.е. подача сигнала всегда предшествует вызову обработчика. Или речь идет о сложных обработчиках, которые могут обрабатывать дольше по времени, чем ожидать приход нового сигнала?

kennydzzze
() автор топика
Ответ на: комментарий от kennydzzze

Или речь идет о сложных обработчиках, которые могут обрабатывать дольше по времени, чем ожидать приход нового сигнала?

Да.

post-factum ★★★★★
()
Ответ на: комментарий от kennydzzze

Сигнал после отработки таймера посылается в функцию sigaction()

Нет. sigaction - сискол, который говорит ядру, что вот этот сигнал приложение хочет обрабатывать с такими флагами и вот таким обработчиком.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Вопрос на будущее: если мне нужно будет обрабатывать больше 1го сигнала, то мне нужно будет предварительно вызвать sigaction() для каждого сигнала? Так вообще можно?

kennydzzze
() автор топика
Ответ на: комментарий от kennydzzze

И если для каждого сигнала свои настройки, то нужно будет еще и свою структуру для каждого сигнала использовать?

kennydzzze
() автор топика
Ответ на: комментарий от kennydzzze

будет предварительно вызвать sigaction для каждого сигнала?

Да, у sigaction номер сигнала не маска, а только номер. Но обработчик может быть общий для нескольких сигналов, для этого у него аргумент - номер полученного сигнала.

vodz ★★★★★
()

и при чём тут таймеры ?

уберите нах printf/scanf из тест-кейса (вообще переработайте тест-кейс), поставьте правильный тип для count, логи пишите в stderr по крайней мере. Вы просто запутались в режимах работы терминала и буферизацией IO.

MKuznetsov ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.