[C, UNIX] два SIGTERM "склеиваются" в один
Возможно он пока в обработчике сигнала, то не принимает ещё один такой же сигнал? Обычные сигналы, они как флаги потому что, в очередь не выстраиваются.
Возможно он пока в обработчике сигнала, то не принимает ещё один такой же сигнал? Обычные сигналы, они как флаги потому что, в очередь не выстраиваются.Вот мы тоже так решили, но это где-нибудь документировано? Нашлись весьма косвенные упоминания в man setrlimit, например. Обработчик, по идее, завершается, но возможно, что просто нельзя последовательно отправить два одинаковых сигнала, на уровне ОС.
Алсо, спросил на SO (если кому интересно).
Возможно он пока в обработчике сигналане
обработчик сигнала делает "do_quit = 1;" и выходит.
pthread_kill со вторым сигтермом вызывается после завершения обработчика первого.
вопрос в том, насколько стандартизовано поведение "не посылать второй из двух одинаковых последовательных сигналов".
имеются ли гарантии на время через которое следующий сигнал уже точно дойдет?
Сейчас в мане нашёл только то, что в обработчике нельзя делать raise.
However, the limit is only enforced for sigqueue(2); it is always possible to use kill(2) to queue one instance of any of the signals that are not already queued to the process.Т.е., очередь сигналов вообще существует для процесса и сигнал игнорируется, если он уже есть в очереди. А обрабатывается сигнал произвольным из незамаскированных на данный сигнал тредов.
обработчик сигнала делает "do_quit = 1;" и выходит.Ну я вообще не помню ничего такого. Т.е. если 2 сразу придёт до обработчика, то 2-й стопудово склется (в single-thread по крайней мере). Но тут-то у него сигнал уже обработан. Поэтому нет никаких причин для 2-го не быть полученным. Тупо взять какой-нибудь демон, который по HUP конфиг перечитывает. Они же на каждый HUP перечитывают, а не только на первый.
pthread_kill со вторым сигтермом вызывается после завершения обработчика первого.
вопрос в том, насколько стандартизовано поведение "не посылать второй из двух одинаковых последовательных сигналов".
имеются ли гарантии на время через которое следующий сигнал уже точно дойдет?
Т.е., очередь сигналов вообще существует для процесса, а сигнал обрабатывается произвольным из незамаскированных на данный сигнал тредов.Ну да, очередь-то есть, чтобы в порядке обрабатывался, но необработанные сигналы не дублируются. В Linux-е для этих целей даже специальные сигналы вроде есть, которые именно накапливаются. SIGRT* кажется.
но второй тред не получает SIGTERM, и соответственно не завершается и висит (как только на сокет приходят данные, то тред завершаетсяНа StackOverflow написано, что когда данные приходят, то TERM всё же обрабатывается. Так как всё же?
Он обрабатывается один раз и тред завершается, так сказать, естественным образом. Т.е., когда тред висит в read, он может быть прерван двумя способами: сигналом (чего не происходит либо ответом read. Во втором случае этого достаточно, т.к. в другом треде флаг завершения выставлен и тред завершается сам, вопрос в том, как обработать первый случай. Точнее сказать, как уже придумали, но это выглядит хаком и хочется понять, чем обосновано такое поведение системы.
void signal_handler(int sig)
{
...
case SIGTERM:
do_quit = 1;
...
}
void th2_proc
{
while (!do_quit)
{
ФУНКЦИЯ_КОТОРАЯ_ЗАСЫПАЕТ_В_ПОЛОЖЕНИИ_READ;
}
}
void ~desctructor
{
pthread_kill(th2_proc, SIGTERM);
}
void th1_proc
{
while (!do_quit)
{
sleep(1);
}
// при завершении th1_proc вызывается деструктор класса
}
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
volatile int do_quit = 0;
void sig_handler(int sig)
{
do_quit = 1;
fprintf(stderr, "sig %d received in %u\n", sig, (unsigned int) pthread_self;
}
void *func(void *arg)
{
fprintf(stderr, "th2: %u\n", (unsigned int) pthread_self;
sleep(1000);
}
int main
{
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
pthread_t th;
pthread_create(&th, NULL, func, NULL);
fprintf(stderr, "th1: %u\n", (unsigned int) pthread_self;
while (!do_quit)
{
}
pthread_kill(th, SIGTERM);
pthread_join(th, NULL);
return 0;
}
Может у тебя, Дима, просто линукс какой-то неправильный? =)
bugaga ~ $ ./a.out
th1: 3076155152
th2: 3076152176
sig 15 received in 3076155152
sig 15 received in 3076152176
ну тогда не только у меня, ибо на енисее такая же проблема была с wz
хотя странно, обработчик-то в либе вообще лежит, ты его не менял.
осилишь из моего примера сделать такой, на котором бага проявляется?
у тебя мой пример работает?
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
volatile int do_quit = 0;
void sig_handler(int sig)
{
do_quit = 1;
fprintf(stderr, "sig %d received in %u\n", sig, (unsigned int) pthread_self;
}
char *host;
void *func(void *arg)
{
fprintf(stderr, "th2: %u\n", (unsigned int) pthread_self;
/* sleep(1000); */
int sd, rc;
sd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(host);
addr.sin_port = htons(80);
rc = connect(sd, (struct sockaddr *) &addr, sizeof(addr;
char buf [4096];
rc = read(sd, buf, 4096);
}
int main(int argc, char **argv)
{
host = argv[1];
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
pthread_t th;
pthread_create(&th, NULL, func, NULL);
fprintf(stderr, "th1: %u\n", (unsigned int) pthread_self;
while (!do_quit)
{
}
pthread_kill(th, SIGINT);
pthread_join(th, NULL);
return 0;
}
вот в этом примере тред получает сигнал, но из read-а не выходит.
странно, я не думал, что sleep в этом смысле сильно отличается от read.
в оригинальном демоне сигнал вообще не доходил, но это из-за программерской ошибки,
так что на самом деле проблема - почему read не завершается.
щас перечитаю про рестарты по сигналу...
проблема 1 (которая моя) разрешилась, просто в обработчике сигнала, в начале, кое-кто написал signal(sig, SIGIGN а я скопипастил...
надо делать вот так
struct sigaction sa;
sigaction(SIGINT, NULL, &sa);
sa.sa_flags &= ~SA_RESTART;
sigaction(SIGINT, &sa, NULL);
этот SA_RESTART (иногда?) по дефолту поднят, и он как раз влияет на то, перезапустится ли read после сигнала.
круто! спасибо, дрюха.
Оставить комментарий
iravik
Есть демон, в котором есть два треда: th1, th2. th2 сидит в чтении сокета.Если послать приложению SIGTERM, th1 ловит сигнал, вызывается деструктор демона, который делает pthread_kill(th2, SIGTERM но второй тред не получает SIGTERM, и соответственно не завершается и висит (как только на сокет приходят данные, то тред завершается).
Если же в декструкторе сделать сначала pthread_kill(th2, 28) (ну или почти любой другой сигнал а потом pthread_kill(th2, SIGTERM то все корректно завершается. Таким образом, возникает ощущение, что приложение игнорирует подряд идущие сигналы.
Подобное "склеивание" сигналов — это стандарт или же зависит от системы? И можно ли как-то послать треду SIGTERM, чтобы этот сигнал точно дошел?