xref: /freebsd-src/lib/libc/stdlib/quick_exit.c (revision 1dc3abb052430279e47c8922d22b30922adcf0f6)
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