LINUX.ORG.RU

«Остановить» блокирующий accept?

 ,


0

3

Привет всем! Вообщем, есть у меня некое многопоточное приложение на C++ с использованием FastCGI.

Так вот, мне нужно его безопасно остановить. Убивать нагло все потоки через pthread_cancel не Ъ. Но по другому не даёт accept (ну хз, больше некому), т.к. он блокирует поток аж до следующего соединения. Как мне сделать так, что бы он остановил блокирование или упал с ошибкой, например? Или может у fcgi есть штатные средства для этого? Пробовал FCGX_ShutdownPending(); и FCGI_SetExitStatus() - результат один и тот же, нужно ждать следующего запроса, что бы убить потоки.


Не используй блокирующий.

anonymous
()

Не менее нагло: делать accept на своей стороне в неблокируещем стиле и отдавать fcgi уже соединенный сокет. Да, это хак. Нужно понимать, что делаешь. Но это лучше, чем pthread_cancel. УМВР.

init () {
    sock = socket (AF_UNIX, SOCK_STREAM, 0);
    flags = fcntl(sock, F_GETFL, 0);
    fcntl(sock, F_SETFL, flags | O_NONBLOCK);
    bind (sock, ...);
    listen (sock, ...);
    ev_io_init (&listener, accept_fcgi, sock, EV_READ);
    ev_io_start (EV_DEFAULT, &listener);
}

accept_fcgi () {
    FCGX_InitRequest(fcgi, sock, 0);
    fcgi.ipcFd = accept (sock, NULL, NULL);
    flags = fcntl(fcgi.ipcFd, F_GETFL, 0);
    fcntl(fcgi.ipcFd, F_SETFL, flags & ~O_NONBLOCK);
    fcgi.keepConnection = FCGI_KEEP_CONN;
    FCGX_Accept_r (&fcgi);
    /*и др. FCGI_* */
}

fopen ★★
()

если есть возможность переписать код вокруг accept то тупо цикл с селектом и таймаутом.

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

Не понимаю о чём ты. Пока handshake не будет завершён соединение не будет считатся установленным, на сокете будет глухо и select будет молчать.

Потом что значит «заблокироваться»? У него есть таймаут который я и предлагаю выставить. Можно сделать ещё хитрее - назначить определённый дескриптор быть индикатором того что надо завершить работу. И делать на него селект вместе с listen_fd.

true_admin ★★★★★
()

Убивать нагло все потоки через pthread_cancel

Зачем убивать нагло? Останови по хорошему. Смотри ман pthread_cancel, state, type

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 1)

pthread_kill попробуй

O02eg ★★★★★
()

хз как там в FastCGI, но если сделать сокету close() в другом потоке, то accept() отваливается с ошибкой. Это конечно фу, так делать не надо, надо select/poll, но иногда больше ничего не придумать

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

В любом случае, он описывал гонку, когда select думает, что делать accept можно, но, на самом деле, тот заблокируется.

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

man 2 accept говорит что select выстрелит когда accept-у будет что вернуть, пусть даже и ошибку, что подтверждается практикой.

Я думаю ты что-то путаешь.

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

ээээ, я 20 минут потыкался в net/ipv4, сходу ничего не понял. В тех функциях что я думаю ответственны за accept ничего такого нет, там чисто идёт забор соединений из очереди. Соотв. в очереди что-то либо есть, либо нету. Смотрел в районе net/ipv4/{tcp_minisocks.c,inet_connection_sock.c}.

Но лучше посмотреть с каким-нить ctags.

PS я после этого стал ненавидить tcp. Голову сломаешь пока разберёшься.

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

Таки да, сигналы можно для этого использовать. Надо добавить:

  • Чтобы FCGX_Accept() завершился при получении сигнала, надо в FCGX_InitRequest передать флаг FCGI_FAIL_ON_INTR.
  • Обработку сигналов нужно взять на себя, т.к. не только ты умеешь их посылать и FCGX_Accept() будет завершаться «неожиданно».
fopen ★★
()

он блокирует поток аж до следующего соединения

Можно сделать себе соединение из второго потока.

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

В любом случае, он описывал гонку, когда select думает, что делать accept можно, но, на самом деле, тот заблокируется.

А он не упоминает, что это актуальный на то время баг? Ведь смысл select'а в том, что если он сработал, это гарантирует неблокируемый read/write. Логично предположить, что это же должно распространяться и на accept(), хотя и выходит, что наплодили сущности.

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

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

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

вдруг сразу после селекта твое приложение будет что-то делать другое (или засуспендится шедулером), а потом захочет accept. но за время «простоя» соединение оборвали.

Тогда accept сразу вернёт ошибку (ECONNABORTED?).

наверное, будет перебор хранить в ядре какое-то состояние для сокета специально для того, чтобы не блокироваться в таких ситуациях.

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

да и вообще, использовать блокирующий сокет и не хотеть заблокироваться - довольно неожиданно.

Для этого и существует select. Ну не заниматься же poll'ингом.

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

окей, так и придется Стивенса заново читать :) возможно теперь в Linux именно так, но Sockets API это же жуткий legacy.

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