1570af302Sopenharmony_ci#include <stdlib.h> 2570af302Sopenharmony_ci#include <stdint.h> 3570af302Sopenharmony_ci#include <stddef.h> 4570af302Sopenharmony_ci#include "libc.h" 5570af302Sopenharmony_ci#include "lock.h" 6570af302Sopenharmony_ci#include "fork_impl.h" 7570af302Sopenharmony_ci#include "dynlink.h" 8570af302Sopenharmony_ci#include "musl_log.h" 9570af302Sopenharmony_ci 10570af302Sopenharmony_ci#define malloc __libc_malloc 11570af302Sopenharmony_ci#define calloc __libc_calloc 12570af302Sopenharmony_ci#define realloc undef 13570af302Sopenharmony_ci#define free __libc_free 14570af302Sopenharmony_ci 15570af302Sopenharmony_ci/* Ensure that at least 32 atexit handlers can be registered without malloc */ 16570af302Sopenharmony_ci#define COUNT 32 17570af302Sopenharmony_ci 18570af302Sopenharmony_cistruct node { 19570af302Sopenharmony_ci void (*func)(void *); 20570af302Sopenharmony_ci void *arg; 21570af302Sopenharmony_ci void *dso; 22570af302Sopenharmony_ci struct dso *internal_dso; // the internal dso weekptr, used for dlclose 23570af302Sopenharmony_ci struct node *prev; 24570af302Sopenharmony_ci struct node *next; 25570af302Sopenharmony_ci}; 26570af302Sopenharmony_ci 27570af302Sopenharmony_cistatic size_t len; // the number of nodes currently in use 28570af302Sopenharmony_cistatic size_t capacity; // the number of available nodes 29570af302Sopenharmony_cistatic struct node builtin[COUNT]; // 32 builtin nodes without malloc 30570af302Sopenharmony_cistatic struct node *tail; // point to the last node, or NULL 31570af302Sopenharmony_cistatic struct node *head; // point to the first node 32570af302Sopenharmony_ci 33570af302Sopenharmony_cistatic volatile int lock[1]; 34570af302Sopenharmony_civolatile int *const __atexit_lockptr = lock; 35570af302Sopenharmony_ci 36570af302Sopenharmony_cistatic int grow() 37570af302Sopenharmony_ci{ 38570af302Sopenharmony_ci struct node *nodes; 39570af302Sopenharmony_ci 40570af302Sopenharmony_ci if (capacity == 0) { 41570af302Sopenharmony_ci nodes = builtin; 42570af302Sopenharmony_ci head = nodes; 43570af302Sopenharmony_ci } else { 44570af302Sopenharmony_ci nodes = malloc(sizeof(struct node) * COUNT); 45570af302Sopenharmony_ci if (nodes == NULL) { 46570af302Sopenharmony_ci return -1; 47570af302Sopenharmony_ci } 48570af302Sopenharmony_ci } 49570af302Sopenharmony_ci 50570af302Sopenharmony_ci for (size_t i = 0; i < COUNT - 1; i++) { 51570af302Sopenharmony_ci nodes[i].next = nodes + (i + 1); 52570af302Sopenharmony_ci } 53570af302Sopenharmony_ci nodes[COUNT - 1].next = NULL; 54570af302Sopenharmony_ci 55570af302Sopenharmony_ci // link new nodes after tail 56570af302Sopenharmony_ci if (tail) { 57570af302Sopenharmony_ci tail->next = nodes; 58570af302Sopenharmony_ci } 59570af302Sopenharmony_ci 60570af302Sopenharmony_ci capacity += COUNT; 61570af302Sopenharmony_ci return 0; 62570af302Sopenharmony_ci} 63570af302Sopenharmony_ci 64570af302Sopenharmony_cistatic void append_node(void (*func)(void *), void *arg, void *dso, struct dso *internal_dso) { 65570af302Sopenharmony_ci struct node *new_tail; 66570af302Sopenharmony_ci if (tail == NULL) { 67570af302Sopenharmony_ci new_tail = head; 68570af302Sopenharmony_ci } else { 69570af302Sopenharmony_ci new_tail = tail->next; 70570af302Sopenharmony_ci } 71570af302Sopenharmony_ci 72570af302Sopenharmony_ci new_tail->func = func; 73570af302Sopenharmony_ci new_tail->arg = arg; 74570af302Sopenharmony_ci new_tail->dso = dso; 75570af302Sopenharmony_ci new_tail->internal_dso = internal_dso; 76570af302Sopenharmony_ci 77570af302Sopenharmony_ci new_tail->prev = tail; 78570af302Sopenharmony_ci tail = new_tail; 79570af302Sopenharmony_ci 80570af302Sopenharmony_ci len++; 81570af302Sopenharmony_ci} 82570af302Sopenharmony_ci 83570af302Sopenharmony_cistatic struct node* remove_node(struct node *node) { 84570af302Sopenharmony_ci struct node *prev = node->prev; 85570af302Sopenharmony_ci if (tail == node) { 86570af302Sopenharmony_ci // move back 87570af302Sopenharmony_ci tail = prev; 88570af302Sopenharmony_ci if (tail == NULL) { 89570af302Sopenharmony_ci head = node; 90570af302Sopenharmony_ci } 91570af302Sopenharmony_ci } else { 92570af302Sopenharmony_ci // remove node 93570af302Sopenharmony_ci struct node *next = node->next; 94570af302Sopenharmony_ci if (next) { 95570af302Sopenharmony_ci next->prev = prev; 96570af302Sopenharmony_ci } 97570af302Sopenharmony_ci if (prev) { 98570af302Sopenharmony_ci prev->next = next; 99570af302Sopenharmony_ci } 100570af302Sopenharmony_ci 101570af302Sopenharmony_ci // insert node after tail 102570af302Sopenharmony_ci struct node *tail_next = tail->next; 103570af302Sopenharmony_ci node->prev = tail; 104570af302Sopenharmony_ci node->next = tail_next; 105570af302Sopenharmony_ci tail->next = node; 106570af302Sopenharmony_ci if (tail_next) { 107570af302Sopenharmony_ci tail_next->prev = node; 108570af302Sopenharmony_ci } 109570af302Sopenharmony_ci } 110570af302Sopenharmony_ci 111570af302Sopenharmony_ci len--; 112570af302Sopenharmony_ci return prev; 113570af302Sopenharmony_ci} 114570af302Sopenharmony_ci 115570af302Sopenharmony_civoid __funcs_on_exit() 116570af302Sopenharmony_ci{ 117570af302Sopenharmony_ci void (*func)(void *), *arg; 118570af302Sopenharmony_ci 119570af302Sopenharmony_ci LOCK(lock); 120570af302Sopenharmony_ci for (; tail; tail = tail->prev) { 121570af302Sopenharmony_ci func = tail->func; 122570af302Sopenharmony_ci tail->func = NULL; // Avoid repeated invocation. 123570af302Sopenharmony_ci if (func != NULL) { 124570af302Sopenharmony_ci arg = tail->arg; 125570af302Sopenharmony_ci UNLOCK(lock); 126570af302Sopenharmony_ci func(arg); 127570af302Sopenharmony_ci LOCK(lock); 128570af302Sopenharmony_ci } 129570af302Sopenharmony_ci } 130570af302Sopenharmony_ci UNLOCK(lock); 131570af302Sopenharmony_ci} 132570af302Sopenharmony_ci 133570af302Sopenharmony_civoid __cxa_finalize(void *dso) 134570af302Sopenharmony_ci{ 135570af302Sopenharmony_ci void (*func)(void *), *arg; 136570af302Sopenharmony_ci struct node *node; 137570af302Sopenharmony_ci 138570af302Sopenharmony_ci LOCK(lock); 139570af302Sopenharmony_ci for (node = tail; node;) { 140570af302Sopenharmony_ci if (dso == node->dso) { 141570af302Sopenharmony_ci func = node->func; 142570af302Sopenharmony_ci if (func != NULL) { 143570af302Sopenharmony_ci arg = node->arg; 144570af302Sopenharmony_ci UNLOCK(lock); 145570af302Sopenharmony_ci func(arg); 146570af302Sopenharmony_ci LOCK(lock); 147570af302Sopenharmony_ci } 148570af302Sopenharmony_ci 149570af302Sopenharmony_ci node = remove_node(node); 150570af302Sopenharmony_ci continue; 151570af302Sopenharmony_ci } 152570af302Sopenharmony_ci 153570af302Sopenharmony_ci node = node->prev; 154570af302Sopenharmony_ci } 155570af302Sopenharmony_ci 156570af302Sopenharmony_ci UNLOCK(lock); 157570af302Sopenharmony_ci} 158570af302Sopenharmony_ci 159570af302Sopenharmony_cistatic void call(void *p); 160570af302Sopenharmony_ci__attribute__ ((__weak__)) extern void *addr2dso(size_t a); 161570af302Sopenharmony_ci 162570af302Sopenharmony_ciint __cxa_atexit(void (*func)(void *), void *arg, void *dso) 163570af302Sopenharmony_ci{ 164570af302Sopenharmony_ci struct dso *p = NULL; 165570af302Sopenharmony_ci LOCK(lock); 166570af302Sopenharmony_ci 167570af302Sopenharmony_ci#if (defined(FEATURE_ATEXIT_CB_PROTECT)) 168570af302Sopenharmony_ci if ((func == (void *)call) && (dso == NULL)) { 169570af302Sopenharmony_ci if (addr2dso != NULL) { 170570af302Sopenharmony_ci p = addr2dso((size_t)arg); 171570af302Sopenharmony_ci if (p == NULL) { 172570af302Sopenharmony_ci UNLOCK(lock); 173570af302Sopenharmony_ci MUSL_LOGE("call atexit with invalid callback ptr=%{public}p", arg); 174570af302Sopenharmony_ci return -1; 175570af302Sopenharmony_ci } 176570af302Sopenharmony_ci } 177570af302Sopenharmony_ci } 178570af302Sopenharmony_ci#endif 179570af302Sopenharmony_ci 180570af302Sopenharmony_ci if (len >= capacity) { 181570af302Sopenharmony_ci if (grow()) { 182570af302Sopenharmony_ci UNLOCK(lock); 183570af302Sopenharmony_ci return -1; 184570af302Sopenharmony_ci } 185570af302Sopenharmony_ci } 186570af302Sopenharmony_ci 187570af302Sopenharmony_ci append_node(func, arg, dso, p); 188570af302Sopenharmony_ci 189570af302Sopenharmony_ci UNLOCK(lock); 190570af302Sopenharmony_ci return 0; 191570af302Sopenharmony_ci} 192570af302Sopenharmony_ci 193570af302Sopenharmony_cistatic void call(void *p) 194570af302Sopenharmony_ci{ 195570af302Sopenharmony_ci if (p != NULL) 196570af302Sopenharmony_ci ((void (*)(void))(uintptr_t)p)(); 197570af302Sopenharmony_ci} 198570af302Sopenharmony_ci 199570af302Sopenharmony_ciint atexit(void (*func)(void)) 200570af302Sopenharmony_ci{ 201570af302Sopenharmony_ci return __cxa_atexit(call, (void *)(uintptr_t)func, 0); 202570af302Sopenharmony_ci} 203570af302Sopenharmony_ci 204570af302Sopenharmony_ciint invalidate_exit_funcs(struct dso *p) 205570af302Sopenharmony_ci{ 206570af302Sopenharmony_ci struct node *node; 207570af302Sopenharmony_ci 208570af302Sopenharmony_ci LOCK(lock); 209570af302Sopenharmony_ci for (node = tail; node; node = node->prev) { 210570af302Sopenharmony_ci // if found exit callback relative to this dso, and 211570af302Sopenharmony_ci if (p == node->internal_dso) { 212570af302Sopenharmony_ci if ((node->dso == NULL) && node->func == (void *)call) { 213570af302Sopenharmony_ci MUSL_LOGD("invalidate callback ptr=%{public}p when uninstall %{public}s", node->arg, p->name); 214570af302Sopenharmony_ci node->arg = NULL; 215570af302Sopenharmony_ci } 216570af302Sopenharmony_ci } 217570af302Sopenharmony_ci } 218570af302Sopenharmony_ci UNLOCK(lock); 219570af302Sopenharmony_ci 220570af302Sopenharmony_ci return 0; 221570af302Sopenharmony_ci}