10a31efe0SDavid Chisnall /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3d915a14eSPedro F. Giffuni *
40a31efe0SDavid Chisnall * Copyright (c) 2011 David Chisnall
5*1dc3abb0SDag-Erling Smørgrav * Copyright (c) 2023 Klara, Inc.
60a31efe0SDavid Chisnall * All rights reserved.
70a31efe0SDavid Chisnall *
80a31efe0SDavid Chisnall * Redistribution and use in source and binary forms, with or without
90a31efe0SDavid Chisnall * modification, are permitted provided that the following conditions
100a31efe0SDavid Chisnall * are met:
110a31efe0SDavid Chisnall * 1. Redistributions of source code must retain the above copyright
120a31efe0SDavid Chisnall * notice, this list of conditions and the following disclaimer.
130a31efe0SDavid Chisnall * 2. Redistributions in binary form must reproduce the above copyright
140a31efe0SDavid Chisnall * notice, this list of conditions and the following disclaimer in the
150a31efe0SDavid Chisnall * documentation and/or other materials provided with the distribution.
160a31efe0SDavid Chisnall *
170a31efe0SDavid Chisnall * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
180a31efe0SDavid Chisnall * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190a31efe0SDavid Chisnall * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200a31efe0SDavid Chisnall * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
210a31efe0SDavid Chisnall * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
220a31efe0SDavid Chisnall * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
230a31efe0SDavid Chisnall * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
240a31efe0SDavid Chisnall * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
250a31efe0SDavid Chisnall * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
260a31efe0SDavid Chisnall * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
270a31efe0SDavid Chisnall * SUCH DAMAGE.
280a31efe0SDavid Chisnall */
290a31efe0SDavid Chisnall
306a96a39cSKonstantin Belousov #include <sys/types.h>
31*1dc3abb0SDag-Erling Smørgrav
32*1dc3abb0SDag-Erling Smørgrav #include <stdatomic.h>
330a31efe0SDavid Chisnall #include <stdlib.h>
340a31efe0SDavid Chisnall
350a31efe0SDavid Chisnall /**
36*1dc3abb0SDag-Erling Smørgrav * Linked list of quick exit handlers. These will be invoked in reverse
37*1dc3abb0SDag-Erling Smørgrav * order of insertion when quick_exit() is called. This is simpler than
38*1dc3abb0SDag-Erling Smørgrav * the atexit() version, because it is not required to support C++
39*1dc3abb0SDag-Erling Smørgrav * destructors or DSO-specific cleanups.
400a31efe0SDavid Chisnall */
410a31efe0SDavid Chisnall struct quick_exit_handler {
420a31efe0SDavid Chisnall struct quick_exit_handler *next;
430a31efe0SDavid Chisnall void (*cleanup)(void);
440a31efe0SDavid Chisnall };
450a31efe0SDavid Chisnall
46*1dc3abb0SDag-Erling Smørgrav static _Atomic(struct quick_exit_handler *) handlers;
470a31efe0SDavid Chisnall
480a31efe0SDavid Chisnall int
at_quick_exit(void (* func)(void))490a31efe0SDavid Chisnall at_quick_exit(void (*func)(void))
500a31efe0SDavid Chisnall {
514fb45508SDavid Chisnall struct quick_exit_handler *h;
524fb45508SDavid Chisnall
53*1dc3abb0SDag-Erling Smørgrav if ((h = calloc(1, sizeof(*h))) == NULL) {
54*1dc3abb0SDag-Erling Smørgrav return (-1);
55*1dc3abb0SDag-Erling Smørgrav }
560a31efe0SDavid Chisnall h->cleanup = func;
57*1dc3abb0SDag-Erling Smørgrav while (!atomic_compare_exchange_strong(&handlers, &h->next, h)) {
58*1dc3abb0SDag-Erling Smørgrav /* nothing */ ;
59*1dc3abb0SDag-Erling Smørgrav }
60e86328cbSDavid Chisnall return (0);
610a31efe0SDavid Chisnall }
620a31efe0SDavid Chisnall
63e86328cbSDavid Chisnall void
quick_exit(int status)64e86328cbSDavid Chisnall quick_exit(int status)
650a31efe0SDavid Chisnall {
66e86328cbSDavid Chisnall struct quick_exit_handler *h;
67e86328cbSDavid Chisnall
680a31efe0SDavid Chisnall /*
690a31efe0SDavid Chisnall * XXX: The C++ spec requires us to call std::terminate if there is an
700a31efe0SDavid Chisnall * exception here.
710a31efe0SDavid Chisnall */
72*1dc3abb0SDag-Erling Smørgrav for (h = atomic_load_explicit(&handlers, memory_order_acquire);
73*1dc3abb0SDag-Erling Smørgrav h != NULL; h = h->next) {
740a31efe0SDavid Chisnall h->cleanup();
756a96a39cSKonstantin Belousov }
760a31efe0SDavid Chisnall _Exit(status);
770a31efe0SDavid Chisnall }
78