Глупые поточные ошибки

Про глупую ошибку в собственном коде писать несколько стыдно, но я попробую. Вдруг кому-нибудь поможет.

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

Однако в reentrant версию тоже не всегда можно зайти дважды.

Конкретная функция называлась ctime_r, и вызывалась из процедуры записи строчки в лог. Изредка программа зависала, причем в стеке фигурировал именно ctime_r. Она же reentrant, WTF?!

Ключевая ошибка заключалась в том, что reentrant – не значит, что без side-effect-ов, и уж тем более не значит – что код можно прервать на любом месте.

Причем в случае с asctime_r, например, как раз можно прервать на любом месте: там действительно нет side-effects. Но не ctime_r (и не localtime_r)!

Это потому, что reenterability конкретно в случае ctime_r в одной из внутренних функций (__tz_convert) делается при помощи mutex-а. (Дело было на Linux, несложно посмотреть исходники.)

И вот когда случается вызов того ctime_r из того же потока, но прерванного сигналом, попытка заблокировать mutex виснет в syscall навсегда.

Век живи, век учись, бдительность ни на секунду не теряй: реэнтерабельность бывает разная.

  • antoxa

    есть такая штука просто async-signal-safe.- функции которые можно вызывать из signal handler.
    в man sigaction они перечислены (http://www.hmug.org/man/2/sigaction.php)

  • http://alexwwolf.livejournal.com/ alexwwolf

    Интересно, но я всегда считал, что reentrant как раз и подразумевает отсутствие side-effects и проблем с произвольным прерыванием.

    http://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B5%D0%BD%D1%82%D0%B5%D1%80%D0%B0%D0%B1%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D1%8C

  • antoxa

    просто суффикс _r никоим боком не означает reentrant, это просто выдаете желаемое за действительное :)

  • IronPeter

    Как бы да, реентерабельность обычно понимается в другом смысле. Не в многопоточном смысле.

    Вот был DOS, многие писали TSR приложения ( устанавливали свои прерывания ). Там нельзя было использовать сервисы DOS ( вызывать прерывания ). Говорили, что DOS нереентерабельна. Поток – один. Савсем адын.

  • GeneralGDA

    В man под Solaris в конце странички по к-л. функции обычно пишется на сколько безопасно использовать функцию в многопоточной программе. Там флагов больше, чем 3. Вроде обзывается MT level.

  • shodan

    > я всегда считал, что reentrant как раз и подразумевает отсутствие side-effects и проблем с произвольным прерыванием.

    Те. минимум одного человека я навел на правильные мысли?
    Могу умирать спокойно.