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 <pthread.h> 31 #include <stddef.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include "un-namespace.h" 35 36 #include "libc_private.h" 37 38 #define DTORS_ITERATIONS 5 39 40 struct thread_dtorfn { 41 void (*func)(void *); 42 void *arg; 43 void *dso; 44 LIST_ENTRY(thread_dtorfn) entry; 45 }; 46 static __thread LIST_HEAD(dtor_list, thread_dtorfn) dtors = 47 LIST_HEAD_INITIALIZER(dtors); 48 49 int __cxa_thread_atexit_impl(void (*func)(void *), void *arg, void *dso); 50 51 void 52 _thread_finalize(void) 53 { 54 struct dl_phdr_info phdr_info; 55 struct thread_dtorfn *fnp, *tdtor; 56 int i; 57 58 /* 59 * It is possible to get more destructors registered while 60 * unregistering them on thread exit. Use maximum DTORS_ITERATIONS 61 * loops. If dso is no longer available (dlclose()), skip it. 62 */ 63 for (i = 0; i < DTORS_ITERATIONS && !LIST_EMPTY(&dtors); i++) { 64 LIST_FOREACH_MUTABLE(fnp, &dtors, entry, tdtor) { 65 LIST_REMOVE(fnp, entry); 66 if (_rtld_addr_phdr(fnp->dso, &phdr_info) && 67 __elf_phdr_match_addr(&phdr_info, fnp->func)) 68 fnp->func(fnp->arg); 69 free(fnp); 70 } 71 } 72 } 73 74 int 75 __cxa_thread_atexit_impl(void (*func)(void *), void *arg, void *dso) 76 { 77 struct thread_dtorfn *fnp; 78 79 fnp = calloc(1, sizeof(*fnp)); 80 if (fnp == NULL) 81 return -1; 82 83 fnp->func = func; 84 fnp->arg = arg; 85 fnp->dso = dso; 86 LIST_INSERT_HEAD(&dtors, fnp, entry); 87 88 return 0; 89 } 90