exit(3): make it thread-safe

It was explained by Rich Felker <dalias@libc.org> on libc-coord.
See https://austingroupbugs.net/view.php?id=1845.

Reviewed by:	imp, markj
Tested by:	antoine (exp-run)
Sponsored by:	The FreeBSD Foundation
MFC after:	1 month
Differential revision:	https://reviews.freebsd.org/D46108
This commit is contained in:
Konstantin Belousov 2024-07-24 23:41:32 +03:00
parent 31f688a26d
commit 3f3ec4b99f
2 changed files with 39 additions and 1 deletions

View file

@ -29,7 +29,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd August 5, 2021
.Dd July 24, 2024
.Dt EXIT 3
.Os
.Sh NAME
@ -102,6 +102,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

View file

@ -31,6 +31,7 @@
#include "namespace.h"
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "un-namespace.h"
@ -48,6 +49,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.
*/
@ -59,6 +74,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.