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)

Причём здесь bash, болезный?

цикл while (1) не должен допускать этого

Кто тебе это сказал?

терминал работает в неканоническом режиме.

Ну…

Но, по идее, это не должно влиять на работу обработчика сигнала.

Ну…

В чем может быть проблема?

Или в твоём коде, который ты не хочешь показывать, или в тебе.

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

Как правильно вывести возвращаемое значение функции signal? Присвоить глобальной переменной самый первый ее вызов и при поступлении сигнала в обработчике выводить эту переменную? Про strace надо читать, ни разу не пользовался ею, но это уже только завтра.

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

В моем реальном коде есть флаги, которые во время работы таймера не дают исправлять эти самые глобальные переменные. Поэтому я сомневаюсь, что ошибка может быть из-за этого.

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

Подожди, оно у тебя ещё и многопоточное?

Может это будет грубым, но лучше почитай 'man signal', это будет лучше моего пересказа, да к тому же я не знаю подробностей твоего секретного кода.

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

Да, но это обычная лаба для универа. Суть в том, что есть массив на 100 элементов, значения которого можно менять при выборе нужной ячейки. Если нажать одну кнопку, то запускается таймер, который просто перебирает все эти ячейки с заданным интервалом. Во время этого перебора я запрещаю пользователю что-либо делать с интерфейсом, но при этом цикл все равно выполняет фиктивные итерации, по крайней мере должен их выполнять, а не завершаться после первой отработки сигнала SIGALRM. Читал я man, ничего полезного не смог найти именно для моей проблемы. Разве что мог не понять правильно то, что читал 10 раз.

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

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

А по фотографии могу нагадать не использовать сигналы там, где не нужно. Может, ты хочешь timerfd+epoll?

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

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

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

Думаю что его лабораторка именно по сигналам)

itn ★★★
()

чтобы вызвать сигнал alarm, нужно вызвать

man 2 alarm

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

Довольно таки бесцеремонный поступок.

Какой именно? Написать тебе письмо или попытка решить лабу чужими силами?

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

Я вроде как на форуме сижу, а не занимаюсь решением чьих-то лаб в привате. Почему так сложно показать код публично?..

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

А вам не все равно каким образом вы собрались помогать? Вас за язык никто не тянул. Или вы уже передумали? Я вроде ясно написал, что публично код предоставить не могу по многим причинам. Странные вы маневры проводите.

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

Обижаете, лабу делаю я сам от и до, не вижу ничего постыдного в том, чтобы спросить помощь на форуме. Хотя, зачем я оправдываюсь?

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

Конечно, не всё равно. Не дерзите, гражданин :).

--- current_result/Makefile     2017-05-06 19:38:00.012943056 +0200
+++ current_result~/Makefile    2017-05-07 08:40:00.561229511 +0200
@@ -1,4 +1,4 @@
-RULES = -Wall -pedantic -std=c99
+RULES = -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L
 
 program: main.o myReadkey.o myBigChars.o myTerm.o mySimpleComputer.o
      gcc -o ./program obj/main.o obj/myReadkey.o obj/myBigChars.o obj/myTerm.o obj/mySimpleComputer.o $(RULES) -lm
diff -Naur current_result/src/main.c current_result~/src/main.c
--- current_result/src/main.c   2017-05-07 02:48:00.012943056 +0200
+++ current_result~/src/main.c  2017-05-07 08:41:40.281533578 +0200
@@ -130,7 +130,11 @@
 
     //Таймер
     flag.timerIgnore = 1;
-    signal(SIGALRM, signalhandler); //принимаю сигнал, обработчик signalhandler описывается с 796 строки
+
+     struct sigaction act;
+     act.sa_handler = signalhandler;
+     act.sa_flags = SA_RESTART;
+     sigaction(SIGALRM, &act, NULL);
 
     //Интерактив
     posvm.minX = 0;

И читайте внимательнее о таймерах.

post-factum ★★★★★
()
Последнее исправление: post-factum (всего исправлений: 1)
Ответ на: комментарий от kennydzzze

И еще, касается всех, вы сами-то осилите просмотр 2к строк кода? Вот и я думаю, что нет. Все изначально было продумано и написано компактно, сохраняя структуру main'a реальной программы. Если и другие обитатели форума не знают тонкостей работы сигналов, которые далеко не очевидные, то о чем вообще может тогда идти разговор? п.с. Лучше молчать, чем предлагать помощь в реальном коде, а потом жаловаться, что тебе его показали.

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

Спасибо. Это было написано до вашего нового поста. К тому же, вы используете другую функцию для принятия сигнала, если сможете получить тот же результат, используя signal(), то искренне поаплодирую вам стоя.

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

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

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

Да, не нужно использовать старое дерьмецо:

CONFORMING TO
4.3BSD, POSIX.1-2001. POSIX.1-2008 marks siginterrupt() as obsolete, recommending the use of sigaction(2) with the SA_RESTART flag
instead.

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

Потому что код разный, и функции ведут себя по-разному при получении сигнала.

Реально, вбей в гугл SA_RESTART и почитай, ну.

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

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

kennydzzze
() автор топика
Ответ на: комментарий от kennydzzze
strace -o log ./program

Для твоего случая хватит.

Side note: руки чешутся высказаться о таких лабах, курсовых и отдельно о качестве кода.

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

Не буду, ибо потрут с 5.1.

Хотя, если коротко и цензурно — слишком много велосипедизма и устаревших приёмов. Если не хочешь объяснять, почему именно сигналы (которые для решения данной задачи, конечно, могут использоваться, но это как забивать гвозди лопатой), объясни, почему не ncurses, например, а своё терминальное спагетти. Смысл лаб/курсовых в процессе или результате?

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

Потому. SA_RESTART позволяет перезапустить любой сискол, имеющий код возврата EINTR, чтобы он не возвращал эту ошибку, а продолжил сою работу. К перезапуску таймера это не относится. Найдите у sigaction/setiitmer этот код возврата... Правильно, ибо они не блокируемые.

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

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

post-factum ★★★★★
()
Последнее исправление: post-factum (всего исправлений: 1)
Ответ на: комментарий от post-factum

Да у него всё не правильно, мне даже коментировать не хочется. И секундный интервал через точный таймер, и получение символа через scanf, и printf в обработчике сигнала. Да всё через одно место...

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

Я о том и говорил, что таймер вручную перезапускать не нужно, когда он вызывается в бесконечном цикле или перед ним. Код в шапке это демонстрирует. Однако в реальном коде, где обработчик сигнала и вызов таймера идентичны этому коду, сигнал SIGALRM не посылается повторно.

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

Это код за 2 минуты, который был написан для примера. Если вас это успокоит, то в реальном коде нажатие клавиш у меня обрабатывает своя функция, основанная на read(), а точный таймер задается микросекундами (50000мкс). А обработчик так вообще возвращает только значение флага.

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

Вы не поняли, я перечислил три первых пункта, остальное лень расписывать. Ваш код ужасен. Без SA_RESTART ваш scanf может положить в ch что угодно, а вы не проверяя ошибку делаете switch(). И так далее.

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

Это вы меня не поняли. Мне все равно как написан этот код в шапке, ибо он только для примера, пусть и грубого.

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

Перезапуск таймера? Вы имеете ввиду остановку таймера? И про какой код идет речь? Про этот в теме или реальный (который видели только вы и я)?

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

Как раз таки эта «хочушка» работает на грубом примере. И такая же «хочушка» в реальном коде, но написанная более гладко НЕ работает.

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

Ты не замечаешь того, что тебе пишут. Ещё раз — ПОЖАЛУЙСТА — запусти свой драгоценный секретный код из-под strace и разберись в том, что получишь.

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

Я хочу понять о чем вы говорили в том посте всего-навсего. Про strace я вас услышал 5 раз, я смотрел его, смотрел конец лога. Все что увидел, так это то, что SIGALRM вызвал команду kill. Но мне это не дает ответа на вопрос - «Почему он это сделал?».

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

То, что ты это наконец увидел и признал — уже хорошо. Дальше хотя бы поверхностно погугли, почему так может происходить.

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