LINUX.ORG.RU

alarm не алармит


0

1

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

Но проблема действительно есть: Первый вызов alarm() устанавливает таймер, в назначенное время приходит сигнал, обрабатывается, все довольны. Обработчик сигнала устанавливается обратно, снова вызывается alarm()... и все. На этом месте начинается бесконечный цикл, прерываемый только ^C.

Суть проги в кратце: компьютер играет сам с собой в кости. Визуализуется бросок крутящейся в терминале палочкой, длительность броска задается вышеозначенным алармом. Принимает два аргумента - время в секундах для каждого из 2 игроков.

Код:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>

unsigned int i;
jmp_buf pos;
char *who[] = {"Com1: ", "Com2: "};
char *ind[] = {"|\b", "/\b", "-\b", "\\\b"};
char digit[] = {"1\n"};

void handler()
{
	static int j=0;
	digit[0] = '1' + i%6;
	write(1, digit, 2);
	longjmp(pos, ++j);
}

int main(int argc, char **argv)
{
	int time[2], j=0;

	if (argc<3 || (time[0] = atoi(argv[1]))<1 || (time[1] = atoi(argv[2]))<1) {
		write(1, "Usage: lab6_19 time1 time2\nTimes must be > 0\n", 45);
		exit(-1);
	}
	
	struct sigaction s;
	memset(&s, 0, sizeof(struct sigaction));
	s.sa_handler = handler;

	if ((j = setjmp(pos)) < 2) {
		sigaction(SIGALRM, &s, 0);
		alarm(time[j]);
		write(1, who[j], 6);
	}
	for (i=getpid()%6; j<2; i++) {
		write(1, ind[i%4], 2);
		usleep(250000);
	}

	exit(0);
}

Результат strace, наглядно иллюстрирующий, что сигнал повторно не приходит:

rt_sigaction(SIGALRM, {0x8048584, [], SA_RESETHAND}, NULL, 8) = 0
alarm(1)                                = 0
write(1, "Com1: "..., 6Com1: )                = 6
getpid()                                = 29333
write(1, "/\10"..., 2)                  = 2
nanosleep({0, 250000000}, NULL)         = 0
write(1, "-\10"..., 2)                  = 2
nanosleep({0, 250000000}, NULL)         = 0
write(1, "\\\10"..., 2)                 = 2
nanosleep({0, 250000000}, NULL)         = 0
write(1, "|\10"..., 2)                  = 2
nanosleep({0, 250000000}, 0)            = ? ERESTART_RESTARTBLOCK (To be restarted)
--- SIGALRM (Alarm clock) @ 0 (0) ---
write(1, "3\n"..., 23
)                   = 2
alarm(1)                                = 0
write(1, "Com2: "..., 6Com2: )                = 6
write(1, "/\10"..., 2)                  = 2
nanosleep({0, 250000000}, NULL)         = 0
write(1, "-\10"..., 2)                  = 2
nanosleep({0, 250000000}, NULL)         = 0
write(1, "\\\10"..., 2)                 = 2
nanosleep({0, 250000000}, NULL)         = 0
write(1, "|\10"..., 2)                  = 2
nanosleep({0, 250000000}, NULL)         = 0
write(1, "/\10"..., 2)                  = 2
nanosleep({0, 250000000}, NULL)         = 0
write(1, "-\10"..., 2)                  = 2
nanosleep({0, 250000000}, NULL)         = 0
write(1, "\\\10"..., 2)                 = 2
nanosleep({0, 250000000}, NULL)         = 0
write(1, "|\10"..., 2)                  = 2
... и далее до бесконечности

Куча write вместо printf и иже с ним - условие лаб.



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

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

Каким образом это по-вашему происходит?

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

Впрочем, пробовал и ручную установку обратно. Все внимание на вывод strace - сигнал не приходит. Да и стандартный обработчик SIGALRM завершает выполнение, так что бесконечного цикле все равно не вышло бы.

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

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

oxcd8o
() автор топика

потому, что в момент работы handler() SIGALRM
заблокирован. он остается blocked и после longjmp().
нужен siglongjmp().

ну, и разумеется, никогда не нужно пользоваться
longjmp(), вообще ;)

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

А вот за разъяснения - отдельное спасибо. Использовать longjmp пришлось по условиям лабы. Сам я бы ни за что)

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