aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsskvor <sskvor@yandex-team.com>2022-11-10 12:04:05 +0300
committersskvor <sskvor@yandex-team.com>2022-11-10 12:04:05 +0300
commit6d5ed9f0166178823f3a752bfe46dd7ef5042df8 (patch)
tree431a578de9d75353b8e60f85d49e74d2370fedf7
parent56418f7c4453670d9fae2c1329fe38c5d81d4563 (diff)
downloadydb-6d5ed9f0166178823f3a752bfe46dd7ef5042df8.tar.gz
[util] Terminate instead of deadlock after fork with running thread pools
Контекст. В древнем странном коде обнаружили, что если создавать `TThreadPool` часто и конкуретно с запуском `TShellCommand`, то иногда последняя дедлочится: если начали выполнять конструктор `TThreadPool` и регистрацию в `TAtforkQueueRestarter`, захватив `TAtforkQueueRestarter::ActionMutex`, а в другом потоке параллельно сделали `fork`, то последний может форкнуться с залоченым мьютексом. Первым делом происходит вызов коллбеков из `pthread_atfork`, где мьютекс лочится заново. Конечно, форкаться в сложных программах с тредпулами категорически запрещено, но, подозреваю, много кода в аркадии так написано. Давайте как-то защитимся от такого.
-rw-r--r--util/thread/pool.cpp12
1 files changed, 8 insertions, 4 deletions
diff --git a/util/thread/pool.cpp b/util/thread/pool.cpp
index a3d4122246..1711048f73 100644
--- a/util/thread/pool.cpp
+++ b/util/thread/pool.cpp
@@ -289,10 +289,14 @@ private:
private:
void ChildAction() {
- with_lock (ActionMutex) {
- for (auto it = RegisteredObjects.Begin(); it != RegisteredObjects.End(); ++it) {
- it->AtforkAction();
- }
+ TTryGuard guard{ActionMutex};
+ // If you get an error here, it means you've used fork(2) in multi-threaded environment and probably created thread pools often.
+ // Don't use fork(2) in multi-threaded programs, don't create thread pools often.
+ // The mutex is locked after fork iff the fork(2) call was concurrent with RegisterObject / UnregisterObject in another thread.
+ Y_VERIFY(guard.WasAcquired(), "Failed to acquire ActionMutex after fork");
+
+ for (auto it = RegisteredObjects.Begin(); it != RegisteredObjects.End(); ++it) {
+ it->AtforkAction();
}
}