LINUX.ORG.RU

Почему может зависнуть вызов localtime()?

 ,


2

4

Есть такая замечательная софтина xrdp. И есть в ней такой замечательный код логгирования:

enum logReturns DEFAULT_CC
log_message(const enum logLevels lvl, const char *msg, ...)
{
    char buff[LOG_BUFFER_SIZE + 31]; /* 19 (datetime) 4 (space+cr+lf+\0) */
    va_list ap;
    int len = 0;
    enum logReturns rv = LOG_STARTUP_OK;
    int writereply = 0;
    time_t now_t;
    struct tm *now;

    if (g_staticLogConfig == NULL)
    {
        g_writeln("The log reference is NULL - log not initialized properly");
        return LOG_ERROR_NO_CFG;
    }

    if (0 > g_staticLogConfig->fd && g_staticLogConfig->enable_syslog == 0)
    {
        return LOG_ERROR_FILE_NOT_OPEN;
    }

    now_t = time(&now_t);
    now = localtime(&now_t);

Так вот, ИНОГДА, при неизвестных обстоятельствах, когда одновременно открывается много сессий, вызов now = localtime(&now_t); наглухо зависает. При этом bt в gdb показывает следующее:

(gdb) bt
#0  __lll_lock_wait_private () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
#1  0x00007f8a100bbabc in _L_lock_2480 () from /lib/x86_64-linux-gnu/libc.so.6
#2  0x00007f8a100bb8f7 in __tz_convert (timer=0x7f8a103c9ee0 <tzset_lock>, use_localtime=1, tp=0x7f8a103ccde0 <_tmbuf>) at tzset.c:627
#3  0x00007f8a10a1441b in log_message (lvl=LOG_LEVEL_INFO, msg=0x7f8a10a1b180 "An established connection closed to endpoint: %s") at log.c:556
#4  0x00007f8a10a1532d in g_tcp_close (sck=9) at os_calls.c:678
#5  0x0000000000405976 in session_start_fork (width=1024, height=768, bpp=24, username=0x7f8a08004a30 "xxx", 
    password=0x7f8a08004a60 "xxx", data=140230816451248, type=1 '\001', domain=0x0, program=0x0, directory=0x0, 
    client_ip=0x7f8a08004a80 "123.0.0.123:59517 - socket: 9") at session.c:523
#6  0x0000000000406bc0 in session_sync_start () at session.c:907
#7  0x00000000004041a5 in sesman_main_loop () at sesman.c:100
#8  0x0000000000404a84 in main (argc=1, argv=0x7fff8cb123d8) at sesman.c:393
(gdb) 

Из-за чего это может быть (сразу скажу, что код в этом месте не многопоточный, хотя форкается куча процессов)?

Система - Ubuntu 14.04. xrdp - 0.9 из git master.

UPD:

(gdb) info threads 
  Id   Target Id         Frame 
* 1    Thread 0x7f891182f740 (LWP 13555) "xrdp-sesman" __lll_lock_wait_private () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
(gdb) 
★★★★★

Последнее исправление: asaw (всего исправлений: 2)
Ответ на: комментарий от pon4ik

Так баг то плавающий. Он то есть, то нет. Я сейчас поменяю, он пропадет, а потом окажется, что это была случайность.

Потом, интересно понять что это за лок такой и почему на нём всё зависает.

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

Я мельком взглянул на код tzset.c, я не силён в сорцах glibc, но похоже, там лок на глобальный статический обьект в шарной либе.

После форка, адресное пространство хоть и cow, однако дескрипторы остаются все те же как и права на них. Поэтому это вполне может быть dead lock на этом «мьютексе».

Вообщем попробуй воспроизвести раз 10. Посчитай сколько попыток затратил. А потом на том же конфиге попробуй воспроизвести с localtime_r, за то же количество попыток.

Может патч пришлёшь этим негодникам использующим небезопасное дрвенее уг.

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

Да, понятно, что там как минимум не будет обращения к коду tzset - уже хорошо...

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

Ну, там уже некий патлатый тип в процессе же :)

Вообще не знал что это known issue. Про лок - знал, про смертельный не знал. В своё время, что бы не спать на таком локе (из соображений производительности) была запиленна либа, которая так то сию проблему решает, т.к. лока там нет в принципе :)

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

pon4ik, хотел вот поинтересоваться: эта библиотека - libdt - точно reentrant? Почему спрашиваю: нашел внутри вызовы функций вроде strftime(), относительно которых таких гарантий, вроде бы, нет. И точно не гарантируется async-signal safety, чего мне бы хотелось.

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

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

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