From: Lennart Poettering Date: Thu, 22 Jun 2023 13:09:50 +0000 (+0200) Subject: async: add explanatory comment X-Git-Tag: v254-rc1~133^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e4687bb8a6a2986642e38b5272694ce21e927679;p=thirdparty%2Fsystemd.git async: add explanatory comment --- diff --git a/src/shared/async.h b/src/shared/async.h index 71d044dd618..96148f9006e 100644 --- a/src/shared/async.h +++ b/src/shared/async.h @@ -6,6 +6,19 @@ #include "macro.h" #include "rm-rf.h" +/* These functions implement various potentially slow operations that are executed asynchronously. They are + * carefully written to not use pthreads, but use fork() or clone() (without CLONE_VM) so that the child does + * not share any memory with the parent process, and thus cannot possibly interfere with the malloc() + * synchronization locks. + * + * Background: glibc only synchronizes malloc() locks when doing fork(), but not when doing clone() + * (regardless if through glibc's own wrapper or ours). This means if another thread in the parent has the + * malloc() lock taken while a thread is cloning, the mutex will remain locked in the child (but the other + * thread won't exist there), with no chance to ever be unlocked again. This will result in deadlocks. Hence + * one has to make the choice: either never use threads in the parent, or never do memory allocation in the + * child, or never use clone()/clone3() and stick to fork() only. Because we need clone()/clone3() we opted + * for avoiding threads. */ + int asynchronous_sync(pid_t *ret_pid); int asynchronous_close(int fd); int asynchronous_rm_rf(const char *p, RemoveFlags flags);