URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 8918
[ Назад ]

Исходное сообщение
"Сигналы и переходы jmp"

Отправлено horse315 , 04-Ноя-10 18:11 
Вашему вниманию несчастное универское задание:

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

Рекомендуется использовать системные вызовы alarm, signal, read и функции setjmp и localjmp.
---

И вот приблизительное решение, которое напрашивается. по идее должно бесконечно задавать вопрос, делая перерывы по 5 сек:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <setjmp.h>
#include <string.h>

jmp_buf jmp;

void pauser(int sig){
    printf("no time no time...\n");
    sleep(5);
    longjmp(jmp,2);
}

int main(){
    char buf[128];
    const char ask[] = "Ioann IV sobriquet?\n";
    const char ans[] = "Grozniy\n";
    setjmp(jmp);
    signal(SIGALRM, pauser);
    alarm(5);
    do{
        write(1, ask, strlen(ask));
        read(0,buf,128);
    }while(strcmp(ans, buf)!=0);
    exit(1);
}

Но вот незадача, первый раз аларм сработал, снова выводится предложение ответить на вопрос и все, тишина) setjmp и alarm не дружат?
Типа:
Ioann IV sobriquet?_
no time no time...
Ioann IV sobriquet?_


Содержание

Сообщения в этом обсуждении
"Сигналы и переходы jmp"
Отправлено ACCA , 05-Ноя-10 10:28 
Так работает:

void pauser(int sig){
    printf("no time no time...\n");
    siglongjmp(jmp,1);
}

int main(){
    char buf[128];
    const char ask[] = "Ioann IV sobriquet?\n";
    const char ans[] = "Grozniy\n";
    signal(SIGALRM, pauser);
    sigsetjmp(jmp, SIGALRM);
    alarm(5);
    do{
        write(1, ask, strlen(ask));
        read(0,buf,128);
    }while(strcmp(ans, buf)!=0);
    exit(1);
}

Поиграйся ещё, обобщи что существенно и напиши здесь, pls.

Неприлично мешать printf и write, выбери что-то одно. Ещё - выбрось \n, используй puts, так считается кошернее, читай с помощью fgets. При этом gets не годится, так как позволяет buffer overflow.


"Сигналы и переходы jmp"
Отправлено horse315 , 05-Ноя-10 11:13 
>[оверквотинг удален]
>     do{
>         write(1, ask, strlen(ask));
>         read(0,buf,128);
>     }while(strcmp(ans, buf)!=0);
>     exit(1);
> }
> Поиграйся ещё, обобщи что существенно и напиши здесь, pls.
> Неприлично мешать printf и write, выбери что-то одно. Ещё - выбрось \n,
> используй puts, так считается кошернее, читай с помощью fgets. При этом
> gets не годится, так как позволяет buffer overflow.

ОО все роскошно, спасибо! снова я man не внимательно прочитал((


"Сигналы и переходы jmp"
Отправлено guest , 06-Ноя-10 16:15 
> Рекомендуется использовать системные вызовы alarm, signal, read и функции setjmp и localjmp.

Вам плохое рекомендуют.
Про longjmp из обработчика лучше забыть (он не восстановит статические переменные libc на момент вызова setjmp), в не учебных программах это может стать причиной больших и трудно отлавливаемых проблем.
Вместо signal лучше посмотрите на sigaction(2) вполне себе POSIX и не надо каждый раз заново переустанавливать обработчик.
printf(3) в обработчике использовать нельзя т.к. это не signal-safe функция. На некоторых *nix можно (v)s(n)printf() и syslog_r, а вот printf я не видел нигде. Список/Ссылка на него функций разрешенных к вызову из обработчика сигнала должен быть в man signal(2)

>     char buf[128];
>         read(0,buf,128);

корректнее все-таки читать sizeof(buf)-1 байт.


> Но вот незадача, первый раз аларм сработал, снова выводится предложение ответить на
> вопрос и все, тишина) setjmp и alarm не дружат?

setjmp не сохраняет маску сигналов (это верно не для всех систем, но например линукс ведет себя именно так), т.е. из обработчика ваш код вываливается с заблокированным SIGALRM и вам надо либо явно разрешить его (sigprocmask(SIG_UNBLOCk,...), либо использовать sigsetjmp