LINUX.ORG.RU

При daemon() процесс попадает в deadlock

 ,


0

2

Один и тот же процесс, вызываемый с флагом --daemonize не выходит по SIGTERM/SIGINT. Запустив его без этого флага, и собственно, без вызова daemon() всё нормально.

Из-за чего так может быть?

0x00007f57b6f28d61 in __futex_abstimed_wait_common64 (private=128, cancel=true, abstime=0x0, op=265, expected=5119, futex_word=0x7f57b6d1d990) at ./nptl/futex-internal.c:57

warning: 57     ./nptl/futex-internal.c: No such file or directory
(gdb) bt
#0  0x00007f57b6f28d61 in __futex_abstimed_wait_common64 (private=128, cancel=true, abstime=0x0, op=265, expected=5119, futex_word=0x7f57b6d1d990) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (cancel=true, private=128, abstime=0x0, clockid=0, expected=5119, futex_word=0x7f57b6d1d990) at ./nptl/futex-internal.c:87
#2  __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x7f57b6d1d990, expected=5119, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=128)
    at ./nptl/futex-internal.c:139
#3  0x00007f57b6f2e793 in __pthread_clockjoin_ex (threadid=140014706087616, thread_return=0x0, clockid=0, abstime=0x0, block=<optimized out>) at ./nptl/pthread_join_common.c:102
#4  0x00007f57b71b9c2b in std::thread::join() () from /lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007f57b7aec504 in std::_Sp_counted_ptr_inplace<nt::mempool_t::pool_impl::memblock_allocation_thread, std::allocator<void>, (__gnu_cxx::_Lock_policy)2>::_M_dispose() ()
   from /opt/nt/lib/libnt.so.1
#6  0x000055aa054abc7e in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use (this=0x55aa05aca9b0) at /usr/include/c++/13/bits/shared_ptr_base.h:175
#7  std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use_cold (this=0x55aa05aca9b0) at /usr/include/c++/13/bits/shared_ptr_base.h:199
#8  0x00007f57b7aea804 in nt::mempool_t::~mempool_t() () from /opt/nt/lib/libnt.so.1
#9  0x000055aa054aaecd in ntproto::stream_storage::~stream_storage (this=0x55aa05ac4cb0, __in_chrg=<optimized out>) at /opt/nt/include/ntproto/ntproto_stream_storage.h:145
#10 std::default_delete<ntproto::stream_storage>::operator() (__ptr=0x55aa05ac4cb0, this=<optimized out>) at /usr/include/c++/13/bits/unique_ptr.h:99
#11 std::unique_ptr<ntproto::stream_storage, std::default_delete<ntproto::stream_storage> >::~unique_ptr (this=0x7ffcb0d09670, __in_chrg=<optimized out>) at /usr/include/c++/13/bits/unique_ptr.h:404
#12 ntproto::stream::~stream (this=0x7ffcb0d09650, __in_chrg=<optimized out>) at /opt/nt/include/ntproto/ntproto_stream.h:35
#13 ntdataflows_stream::~ntdataflows_stream (this=0x7ffcb0d09650, __in_chrg=<optimized out>) at /home/g10/projects/components/nt-dataflows/.build/ntdataflows_stream.h:26
#14 ntdataflows_service::~ntdataflows_service (this=0x7ffcb0d09640, __in_chrg=<optimized out>) at /home/g10/projects/components/nt-dataflows/src/service/ntdataflows_service.cc:565
#15 0x000055aa0549248a in main (argc=<optimized out>, argv=0x7ffcb0d098d8) at /home/g10/projects/components/nt-dataflows/src/service/ntdataflows_service.cc:985

Ответ на: комментарий от utf8nowhere

после fork ниток нет, если действительно юзается fork то это скорей всего man signal-safety
но нужно смотреть в дебаге info threads

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

после fork ниток нет

Спасибо, капитан. Системных нет. Но плюсовые объекты std::thread, например, никуда не деваются. Они, или ntpl где-то внутри себя, или ещё что-то, хранит (ставшую невалидной) инфу о потоках

Похожая проблема, где виснет в деструкторе тредпула после daemon

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

Pita = pain in the ass.

Многопоточное приложение так просто не демонизируешь. daemon() рассчитан на однопоточное приложение. Его можно вызвать до создания потоков. Но результат такой демонизации будет так себе. Фоновый процесс начнёт создавать потоки после выхода из daemon(), словит критическую ошибку, и что ему делать? Ведь об успешной демонизации уже рапортовал успешно завершившийся стартовый процесс.

iliyap ★★★★★
()

В общем, приведенный бектрейс – это бектрейс треда, который запускается в конструкторе глобального объекта, я на этот поток никак не могу повлиять снаружи.

в общем, понятно, что нужно остановить все «лишние» потоки перед fork(). Так как этот поток блокирует мьютекс, после чего вызывается fork() и разблокировать не получится.

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

ничего подобного… утебя :mempool_t::~mempool_t который делает join которому скорей всего это делать не нужно. уметь правильно выходить из fork нужно учиться)

#include <chrono>
#include <thread>
#include <iostream>
#include <unistd.h>

using namespace std::chrono_literals;

int main()
{
    auto thr = std::thread([]()
    {
        for(int ii = 0; ii < 10; ++ii)
        {
            std::cout << "id: " << std::this_thread::get_id() << ", " << ii << std::endl;
            std::this_thread::sleep_for( 1s );
        }
    });

    int pid = fork();

    if(pid)
    {
        std::cout << "pid: " << pid <<std::endl;
        thr.join();
    }
    else
    {
        std::cout << (thr.joinable() ? "111" : "222") <<std::endl;
        execl("/bin/false", "/bin/false", nullptr);
    }

    return 0;
}
anonymous2 ★★★★★
()
Последнее исправление: anonymous2 (всего исправлений: 1)
Ответ на: комментарий от OlegUP

Создание потока в конструкторе, ожидание завершения потока в деструкторе, форки вперемешку с тредами. Вы не ищите лёгких путей, судя по всему.

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

и что ему делать?

Записать в лог и завершить работу? В чём боль, демоны всё пишут в лог, какая разница, когда возникла ошибка, через 100 часов работы или через 100 тактов?

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

На мой взгляд фоновый процесс демона не должен завершаться из-за каких-то ошибок. Если стартовый процесс вернул 0, значит фоновый процесс успешно запущен и будет работать до усрачки. Фоновый процесс должен завершаться только по команде. Иначе это какой-то дефективный демон.

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

ИМХО, любой софт содержит ошибки в коде, если не в настоящем времени, то в грядущем, когда что-то изменять в используемых библиотках. И, по большому счёту без разницы, ошибка в конфиге или в коде, что так, что так процесс (фоновый или переднего плана) «не знает» что неправильно, проще завершаться. Да и вобще, ошибка в коде, она на то и ошибка, что программа завершится независимо от желаний кодера :)

А в мире Unix с overcommit-памятью работать до усрачки вобще непонятно как — зарезервируешь на старте побольше памяти, дак OOM-killer убъёт. Будешь брать память понемногу, получишь SIGSEGV. Если уж делать что-то зубодробильное, то и управляющий сокет демону и отдельно висящая задача, контролирующий не просто, что демон есть в списке процессов, а то, что он правильно работает, не зациклился, не залип на внутренних блокировках.

С тем, что переделывать чужой код может быть БОЛЬ, согласен, но, ИМХО, не важно, в демона или какой-то другой функционал прикручивать...

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

в мире Unix с overcommit-памятью

overcommit – сранный позор.

OOM-killer убъёт.

Лучше хотя бы systemd-oomd настроить или ещё что-то адекватное.

hateyoufeel ★★★★★
()

вызова daemon() всё нормально.

Выкинь каку. Вызов daemon() не нужен уже лет 10 как. Тот же systemd умеет просто запускать процессы и управлять ими. Форкаться, закрывать stdin/out/err или перенаправлять их изнутри программы вообще не требуется.

hateyoufeel ★★★★★
()
Последнее исправление: hateyoufeel (всего исправлений: 1)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.