freebsd-src/lib/libc/stdlib/quick_exit.c
Dag-Erling Smørgrav 1dc3abb052 libc: Rewrite quick_exit() and at_quick_exit() using C11 atomics.
Compiler memory barriers do not prevent the CPU from executing the code
out of order.  Switch to C11 atomics.  This also lets us get rid of the
mutex; instead, loop until the compare_exchange succeeds.

While here, change the return value of at_quick_exit() on failure to
the more traditional -1, matching atexit().

Sponsored by:	Klara, Inc.
Reviewed by:	Olivier Certner, kevans, kib
Differential Revision:	https://reviews.freebsd.org/D41936
2023-09-26 22:07:10 +02:00

78 lines
2.4 KiB
C

/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2011 David Chisnall
* Copyright (c) 2023 Klara, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <stdatomic.h>
#include <stdlib.h>
/**
* Linked list of quick exit handlers. These will be invoked in reverse
* order of insertion when quick_exit() is called. This is simpler than
* the atexit() version, because it is not required to support C++
* destructors or DSO-specific cleanups.
*/
struct quick_exit_handler {
struct quick_exit_handler *next;
void (*cleanup)(void);
};
static _Atomic(struct quick_exit_handler *) handlers;
int
at_quick_exit(void (*func)(void))
{
struct quick_exit_handler *h;
if ((h = calloc(1, sizeof(*h))) == NULL) {
return (-1);
}
h->cleanup = func;
while (!atomic_compare_exchange_strong(&handlers, &h->next, h)) {
/* nothing */ ;
}
return (0);
}
void
quick_exit(int status)
{
struct quick_exit_handler *h;
/*
* XXX: The C++ spec requires us to call std::terminate if there is an
* exception here.
*/
for (h = atomic_load_explicit(&handlers, memory_order_acquire);
h != NULL; h = h->next) {
h->cleanup();
}
_Exit(status);
}