1 /* 2 * Copyright (c) 2019 The DragonFly Project. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 14 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 15 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 16 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 17 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 23 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/queue.h> 28 #include "namespace.h" 29 #include <link.h> 30 #include <stddef.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include "un-namespace.h" 34 35 #include "libc_private.h" 36 37 #define DTORS_ITERATIONS 5 38 39 struct thread_dtorfn { 40 void (*func)(void *); 41 void *arg; 42 void *dso; 43 LIST_ENTRY(thread_dtorfn) entry; 44 }; 45 static __thread LIST_HEAD(dtor_list, thread_dtorfn) dtors = 46 LIST_HEAD_INITIALIZER(dtors); 47 48 int __cxa_thread_atexit_impl(void (*func)(void *), void *arg, void *dso); 49 50 void 51 _thread_finalize(void) 52 { 53 struct dl_phdr_info phdr_info; 54 struct thread_dtorfn *fnp, *tdtor; 55 int i; 56 57 /* 58 * It is possible to get more destructors registered while 59 * unregistering them on thread exit. Use maximum DTORS_ITERATIONS 60 * loops. If dso is no longer available (dlclose()), skip it. 61 */ 62 for (i = 0; i < DTORS_ITERATIONS && !LIST_EMPTY(&dtors); i++) { 63 LIST_FOREACH_MUTABLE(fnp, &dtors, entry, tdtor) { 64 LIST_REMOVE(fnp, entry); 65 if (_rtld_addr_phdr(fnp->dso, &phdr_info) && 66 __elf_phdr_match_addr(&phdr_info, fnp->func)) 67 fnp->func(fnp->arg); 68 free(fnp); 69 } 70 } 71 } 72 73 int 74 __cxa_thread_atexit_impl(void (*func)(void *), void *arg, void *dso) 75 { 76 struct thread_dtorfn *fnp; 77 78 fnp = calloc(1, sizeof(*fnp)); 79 if (fnp == NULL) 80 return -1; 81 82 fnp->func = func; 83 fnp->arg = arg; 84 fnp->dso = dso; 85 LIST_INSERT_HEAD(&dtors, fnp, entry); 86 87 return 0; 88 } 89