git: 8d801641a398 - stable/14 - exit(3): make it thread-safe

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Wed, 21 Aug 2024 10:33:22 UTC
The branch stable/14 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=8d801641a39834cf8ce72dc88cf8bc5712cc1cad

commit 8d801641a39834cf8ce72dc88cf8bc5712cc1cad
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-07-24 20:41:32 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-08-21 10:32:49 +0000

    exit(3): make it thread-safe
    
    (cherry picked from commit 3f3ec4b99f79d32a0bf15495559ca9883bd751f2)
---
 lib/libc/stdlib/exit.3 | 20 ++++++++++++++++++--
 lib/libc/stdlib/exit.c | 21 +++++++++++++++++++++
 2 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/lib/libc/stdlib/exit.3 b/lib/libc/stdlib/exit.3
index afdc58ec4831..c190f5fac27f 100644
--- a/lib/libc/stdlib/exit.3
+++ b/lib/libc/stdlib/exit.3
@@ -29,9 +29,8 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"     @(#)exit.3	8.1 (Berkeley) 6/4/93
 .\"
-.Dd August 5, 2021
+.Dd July 24, 2024
 .Dt EXIT 3
 .Os
 .Sh NAME
@@ -104,6 +103,23 @@ values described in
 .Xr sysexits 3
 may be used to provide more information to the parent process.
 .Pp
+Calls to the
+.Fn exit
+function are serialized.
+All functions registered by
+.Xr atexit 3
+are executed in the first thread that called
+.Nm exit .
+If any other thread of the process calls
+.Nm exit
+before all registered functions have completed or before the process
+terminates, the thread is blocked until the process terminates.
+The exit status of the process is the
+.Fa status
+argument of the first
+.Nm exit
+call which thread proceeds the atexit handlers.
+.Pp
 Note that
 .Fn exit
 does nothing to prevent bottomless recursion should a function registered
diff --git a/lib/libc/stdlib/exit.c b/lib/libc/stdlib/exit.c
index a0c9622944c5..b2c2fa7db4bb 100644
--- a/lib/libc/stdlib/exit.c
+++ b/lib/libc/stdlib/exit.c
@@ -34,6 +34,7 @@ static char sccsid[] = "@(#)exit.c	8.1 (Berkeley) 6/4/93";
 #endif /* LIBC_SCCS and not lint */
 #include "namespace.h"
 #include <stdlib.h>
+#include <pthread.h>
 #include <unistd.h>
 #include "un-namespace.h"
 
@@ -51,6 +52,20 @@ void (*__cleanup)(void);
  */
 int	__isthreaded	= 0;
 
+static pthread_mutex_t exit_mutex;
+static pthread_once_t exit_mutex_once = PTHREAD_ONCE_INIT;
+
+static void
+exit_mutex_init_once(void)
+{
+	pthread_mutexattr_t ma;
+
+	_pthread_mutexattr_init(&ma);
+	_pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
+	_pthread_mutex_init(&exit_mutex, &ma);
+	_pthread_mutexattr_destroy(&ma);
+}
+
 /*
  * Exit, flushing stdio buffers if necessary.
  */
@@ -62,6 +77,12 @@ exit(int status)
 
 	_thread_autoinit_dummy_decl = 1;
 
+	/* Make exit(3) thread-safe */
+	if (__isthreaded) {
+		_once(&exit_mutex_once, exit_mutex_init_once);
+		_pthread_mutex_lock(&exit_mutex);
+	}
+
 	/*
 	 * We're dealing with cleaning up thread_local destructors in the case of
 	 * the process termination through main() exit.