LINUX.ORG.RU

Вызов poll рвется RT-сигналом, у которого стоит флаг SA_RESTART. Что делать?!


0

0

Ситуация примерно следующая. Есть мультитредовое приложение, работает
под NPTL only (LinuxThreads меня не интересует). На сигнал SIGRT_3
навешивается некоторое действие. При этом выставляется флаг sigaction
SA_RESTART. Один из потоков приложения садится на poll. Вся прилада
обрабатывает сетевые http-запросы (для их генерации я использую Apache
Benchmark, ab).

Так вот, через некоторое время очередной вызов poll возвращает -1,
errno = EINTR, и в логе strace случается такая запись:

poll([{fd=15, events=POLLIN}, {fd=30, events=POLLOUT}], 2, 0) = -1 EINTR (Interrupted system call)
--- SIGRT_3 (Real-time signal 2) @ 0 (0) ---

До этого в том же логе есть только записи

rt_sigaction(SIGRT_3, {0x404314e0, ~[RTMIN], SA_RESTART|SA_SIGINFO}, {SIG_DFL}, 8) = 0
..................................................
tgkill(12740, 12743, SIGRT_3) = 0
..................................................
poll([{fd=15, events=POLLIN, revents=POLLIN}, {fd=18, events=POLLOUT, revents=POLLOUT}, {fd=21, events=POLLIN, revents=POLLIN}, {fd=20, events=POLLIN, revents=POLLIN}, {fd=22, events=POLLIN}, {fd=19, events=POLLIN}], 6, 0) = 4
..................................................
--- SIGRT_3 (Real-time signal 2) @ 0 (0) ---
..................................................

То есть все идет как задумано...

Ну как может poll порваться-то? Я не просекаю... Может быть, это
баг в ядре? У меня 2.6.7, 2.6.8 - происходит одно и то же. NPTL
версии 0.61.

Заранее спасибо за любую помощь!


Легко, Linux много где по сигналу возвращает EINTR вместо ERESTART. Ты сам то в код посмотри: fs/select.c это вроде. :)

Вообще, ряд системных вызовов считается non-restartable by design, так что флажки вроде SA_RESTART - это вилами по воде... но вполне может быть и обычным раздолбайством. :)

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

не так просто сделать вызов с таймаутом restartable.

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

если никакого сигнала реально не доставлялось (например
SIG_IGN), то в 2.6 это можно реализовать с помощью
restart_block, иначе и непонятно, как это сделать.

интересно, что стандарты про это говорят, никто не знает?

на всякий случай, проблему вашу легко обойти:
do err = poll(); while (err < 0 && errno == EINTR),
но вы, наверное, это и сами понимаете.

idle ★★★★★
()

А почему NPTL only и чем оно лучше LinuxThreads ?

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

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

можно корректировать таймаут по указателю в userspace с учетом jiffies.
по существу проблема - надуманная
но не сомневаюсь разработчики последовали вашей логике

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

Ну тогда такое решение:

системный вызов poll принимает timeout по указателю, POSIX вызов (с таймаутом по значению) реализуется оберткой glibc. Поскольку glibc Linux ABI - фактически в компетенции ядра, то такое решение вполне в компетенции разработчиков ядра.

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

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

2 Murr:

> А, пардон, в poll ведь таймаут передается не по указателю. :)

да можно считать, что по указателю: regs->esi :)

> системный вызов poll принимает timeout по указателю, POSIX вызов (с
> таймаутом по значению) реализуется оберткой glibc.

да можно конечно, только передавать придется не таймаут, а
gettimeofday() + timeout, обработчик сигнала может ведь
и sleep() сделать. тогда sys_poll()'у даже не надо будет
этот параметр менять.

> можно добавить нужную функциональность

а она нужна? повторяю, я не знаю, что стандарты говорят
по этому поводу

> чтобы оно нормально реализовало RESTARTABLE вызовы.

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

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

idle:

>да можно считать, что по указателю: regs->esi :)

На Alpha и Ultrasparc нет esi, кроме того, esi между выходом и повторным входом в ядро ядром не контролируется.

>да можно конечно, только передавать придется не таймаут, а
>gettimeofday() + timeout, обработчик сигнала может ведь
>и sleep() сделать. тогда sys_poll()'у даже не надо будет
>этот параметр менять.

А sleep - это сугубо личное дело обработчика сигнала. Можно ведь и SIGSTOP всегда послать и тем самым надолго отправить нить down, несмотря на любые таймауты. :)

Думаю логичнее считать timeout временем работы poll, для этого как раз удобно иметь переменную на стеке вызова glibc:

int libc_poll (..., int timeout) {
int local_timeout = timeout;
...
sys_poll(..., &local_timeout);
...
}

А в ядре:
{ int start_time = jiffies;
int timeout;
get_user(timeout, libc_timeout);

...
if (signal_pending(current)) {
put_user(timeout-(jiffies-start)*..., libc_timeout);
return ERESTART...;
}
...
}

Тогда при неком разумном поведении обработчиков сигналов (если они не будут спать и делать другие глупости) будет достигаться разумный выход по таймауту.

>а она нужна? повторяю, я не знаю, что стандарты говорят
>по этому поводу

Ну вот автору темы нужна.

Мое личное мнение состоит в том, что если есть концепция (как SA_RESTART), то нужно стремится к тому, чтобы это было не просто флажком. В коде коммерческих UNIX к подобным вещам довольно трепетно относятся (один тут лежит под рукой :)), а в Linux - кое-где сигналы перестартуются, кое-где - нет, кое-где fasync/poll работает, кое-где - нет, на бездисковых файловых системах иногда размер файлов верно показывается, иногда - нет. В 2.6 благо все не так ужасно как в 2.4.

>да, по-моему, и так здесь все неплохо. я, честно говоря,
>не вижу особой проблемы в том, чтобы проверять на EINTR
>или простой wrapper сделать.

Да уж придумать заплатку несложно, но как-то коряво всё это ...

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

Спасибо за ответы.

Обидно, конечно, что такая ерунда с нерестаруемыми сисколлами... Я этого не знал, признаюсь. Кстати, как вообще можно узнать, какие вызовы restartable, а какие нет? Например, select?

Обертку, конечно, я сделал. Причем простую, как говорил Idle.

Да, кстати, я совсем забыл уточнить один забавный факт: проблема проявляется ТОЛЬКО на 2-way машине с SMP kernel 2.6. На остальных конфигурациях (хотя на других, не 2-way SMP системах я не проверял).

Еще раз спасибо.

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

Узнать можно только из кода ядра. Просто нужно аккуратно просмотреть, что может вернуть соответствующая sys-функция. Если она может вернуть EINTR, то будь готов к тому, что в любой момент из системного вызова можно вылететь. Если же только ERESTART*, то могут быть варианты - зависит от того, какие именно ERESTART*, есть ли обработчики и какие флажки стоят на сигналы.

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

> > да можно считать, что по указателю: regs->esi :)
>
> На Alpha и Ultrasparc нет esi,

зато есть pt_regs.u_regs[]

> кроме того, esi между выходом и повторным
> входом в ядро ядром не контролируется.

это как? очень даже контролируются. при повторном входе
в ядро состояния файла регистров будет соостветсвовать
текущему pt_regs.

но, вообще-то, я не зря смайлик там поставил...

> Мое личное мнение состоит в том, что если есть концепция
> (как SA_RESTART), то нужно стремится к тому, чтобы это было
> не просто флажком.

Murr, по-моему вы передергиваете. я в третий раз повторяю,
я не знаю, что говорит стандарт по поводу SA_RESTART poll().
Если он требуется, тогда, возможно это поведение стоит
исправить. возможно, так как какие-то приложения обязательно
поломаются, в linux _очень_ неохотно идут на бинарные несовместимости.
некоторые вызовы nonrestartable by design. вы же не хотите,
чтобы sys_rt_sigsuspend() возвращал ERESTARTSYS?

так что "просто флажок" - эт вы сгоряча :)

теме не менее, если вам известно, поведение каких вызовов
linux в этом смысле не соответсвует стандартам - буду рад
узнать.

> кое-где fasync/poll работает

ну полно драйверов недоделанных, чего говорить. ядро-то
причем. другое дело, что оно все в одно tarball.

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

>зато есть pt_regs.u_regs[]
Слишком платформозависимо и ABI зависимо. :)
На 10-м уровне вложенности будет нетривиально определить откуда пришел аргумент.

>это как? очень даже контролируются. при повторном входе
>в ядро состояния файла регистров будет соостветсвовать
>текущему pt_regs.
Угу, согласен, стормозил.
Но все равно в реалиях неосуществимо (см. выше).

>Murr, по-моему вы передергиваете. я в третий раз повторяю,
>я не знаю, что говорит стандарт по поводу SA_RESTART poll().
>Если он требуется, тогда, возможно это поведение стоит
>исправить. возможно, так как какие-то приложения обязательно
>поломаются, в linux _очень_ неохотно идут на бинарные несовместимости.
>некоторые вызовы nonrestartable by design. вы же не хотите,
>чтобы sys_rt_sigsuspend() возвращал ERESTARTSYS?
Я то передергиваю? Возможно, во всяком случае у меня нет двойных стандартов. Я всего лишь за разумное поведение ОС и реализацию концепций без двойных стандартов. Если у нас есть концепция перезапускаемых вызовов, то она должна работать не после дождичка в четверг, а всегда, за исключением тех вызовов, для которых сигнал по сути имеет особое значение (как pause/sigsuspend).

Чего вы так прицепились к стандартам? Стандарт - не самоцель, главное - чтобы было удобно и логично.

>ну полно драйверов недоделанных, чего говорить. ядро-то
>причем. другое дело, что оно все в одно tarball.
Дык чего к каким-то драйверам ходить?
Даже для банальных pipe/fifo по-моему соответствующая функциональность была дописана только в 2.6.

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

> Чего вы так прицепились к стандартам? Стандарт - не самоцель,
> главное - чтобы было удобно и логично.

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

> Дык чего к каким-то драйверам ходить?
> Даже для банальных pipe/fifo по-моему соответствующая функциональность
> была дописана только в 2.6.

хм, действительно :) что очень странно, делов-то всего
ничего. видно, никому не нужно было :)

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