LINUX.ORG.RU

Когда сигнал может прервать выполнение программы


0

0

Привет!

Рассмотрим ситуацию:
1) Выполняется printf("Hello world\n");
2) Приходит сигнал HUP, который прерывает printf "где-то в середине".
3) В обработчике сигнала я выполняю printf("Fuck world\n");
4) Происходит возврат.

Что будет (точнее может быть) выведено на stdout?

Главный вопрос - в каких местах система может прерывать выполнение
программы?
В любом (где сигнал не блокирован) или есть участки кода, которые
прерваны быть не могут и сингал приходит только после выхода из
этого участка?

Re: Когда сигнал может прервать выполнение программы

Со ссылки, которую я дал:

==={{{
when a signal interrupts an unsafe function and the signal-catching
function calls an unsafe function, the behavior is undefined
===}}}

undefined = "в принципе может произойти всё, что угодно."

execve ()

Re: Когда сигнал может прервать выполнение программы

> Но ведь реально-то я его могу вызвать.

хм, ваши проблемы и проблемы системы коррелируют только в обратную сторону, но никак не в прямую.

asgard ()

Re: Когда сигнал может прервать выполнение программы

Сигнал может даже прервать системный вызов. Так шо sigprocmask в руки для защиты критических секций.

Zmacs ()

Re: Когда сигнал может прервать выполнение программы

А касательно вопроса "Что будет (точнее может быть) выведено на stdout?" - будет либо

"Hello world\n""Fuck world\n"

либо

"Fuck world\n"

выведено. Hello world во первых попадет в кеш libc-а, а во вторых, блок данных менее чем 512 байт пишеться в дескриптор атомарно.

anonymous ()

Re: Когда сигнал может прервать выполнение программы

> А касательно вопроса "Что будет (точнее может быть) выведено на stdout?" - будет либо

Или будет одна из вариаций "Hello woFuck world\nrld\n"

Или, что вероятнее, случится deadlock между двумя printf'ами. google:// printf signal deadlock

execve ()

Re: Когда сигнал может прервать выполнение программы

Нужно смотреть исходиники конкретной libc и определять, реентерабильна (reenterable) ли функция printf. Еще от размера буфера и типа буферизации (функция setvbuf).

В случае LinuxThreads функции libc, вроде бы, используют отдельный мутекс, и тут может случиться и deadlock.

Стандарт четко определяет список функций, которые можно вызывать из обработчика сигнала:

http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html

mky ★★★★★ ()

Re: Когда сигнал может прервать выполнение программы

> Или будет одна из вариаций "Hello woFuck world\nrld\n"

Только в случае тупой реализации printf-а, посимвольно печатающей строчку, а с корее всего printf готовит строку для записи заранее, по этой причине он будет делать write от готовой строки, а write на размер менее чем PIPE_BUF не будет оборван на куски.

anonymous ()

Re: Когда сигнал может прервать выполнение программы

Теоретик, млин.

==={{{
$ сat 1.c
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>

static const char *s = "Hello, world";

static void on_sighup()
{
        printf("Fuck world\n");
}

int
main()
{
        struct sigaction act;
        pid_t pid;
        act.sa_handler = on_sighup;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGHUP, &act, NULL);
        pid = fork();
        if ( ! pid ) {
                while(1) {
                        printf("%s%s%s\n", s, s, s);
                }
        } else {
                while (1) {
                        kill(pid, SIGHUP);
                }
        }
        return 0;
}

$ cc -W -Wall -pedantic -std=c99 1.c -o 1

$ ./1 >|logg

Ctrl-C
$ more logg
...
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
Hello, worldHello, worldFuck worldld
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
Fuck world
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
Hello, worldFuck world
Hello, worldHello, world
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
Fuck world
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
Fuck world
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
...
===}}}

Мало того, на солярке:

==={{{
$ more logg
...
Hello, worldHello, worldHello, woFuck world
rld
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
...
Hello, worldHello, worldHello, world
Hello, wFuck world
orldHello, worldHello, world
Hello, worldHello, worldHello, world
Hello, worldHello, worldHello, world
...
===}}}

Вообще этот спор о сортах говна поднадоел.
printf из обработчика сигнала делать нельзя. Period.
И вменяемые разработчики этому правилу следуют.

А что там в случае использования напечатается никому вобщем-то не интересно.

execve ()

Re: Когда сигнал может прервать выполнение программы

> printf из обработчика сигнала делать нельзя. Period.

Это неправда. async-signal-unsafe функции можно вызывать из обработчика сигнала. Просто в этом случае их нельзя вызывать в основном теле программы.

Но зачем такое может понадобиться - ума не приложу ;)

anonymous ()

Re: Когда сигнал может прервать выполнение программы

> Это неправда. async-signal-unsafe функции можно вызывать из обработчика сигнала. Просто в этом случае их нельзя вызывать в основном теле программы.

...а так же нельзя вызывать в основном теле программы все функции, которые в свою очередь вызываются небезопасным вызовом. у вас есть уверенность, что printf() ни при каких условиях не вызывает, скажем, malloc()? независимо от платформы? у меня вот нет такой уверенности бо быть её не может. нет, ну конечно, если вы не вызываете malloc() то без проблем :)

// wbr

klalafuda ★☆☆ ()

Re: Когда сигнал может прервать выполнение программы


ps: это я к тому, что утверждение "в обработчика сигнала *нельзя* вызывать printf()" верно без всяких "если". просто нельзя. c'est la vie.

// wbr

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