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 g_len; // the number of nodes currently in use 28570af302Sopenharmony_cistatic size_t g_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 (g_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 g_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{ 66570af302Sopenharmony_ci struct node *new_tail; 67570af302Sopenharmony_ci if (tail == NULL) { 68570af302Sopenharmony_ci new_tail = head; 69570af302Sopenharmony_ci } else { 70570af302Sopenharmony_ci new_tail = tail->next; 71570af302Sopenharmony_ci } 72570af302Sopenharmony_ci 73570af302Sopenharmony_ci new_tail->func = func; 74570af302Sopenharmony_ci new_tail->arg = arg; 75570af302Sopenharmony_ci new_tail->dso = dso; 76570af302Sopenharmony_ci new_tail->internal_dso = internal_dso; 77570af302Sopenharmony_ci 78570af302Sopenharmony_ci new_tail->prev = tail; 79570af302Sopenharmony_ci tail = new_tail; 80570af302Sopenharmony_ci 81570af302Sopenharmony_ci g_len++; 82570af302Sopenharmony_ci} 83570af302Sopenharmony_ci 84570af302Sopenharmony_cistatic struct node* RemoveNode(struct node *node) 85570af302Sopenharmony_ci{ 86570af302Sopenharmony_ci struct node *prev = node->prev; 87570af302Sopenharmony_ci if (tail == node) { 88570af302Sopenharmony_ci // move back 89570af302Sopenharmony_ci tail = prev; 90570af302Sopenharmony_ci if (tail == NULL) { 91570af302Sopenharmony_ci head = node; 92570af302Sopenharmony_ci } 93570af302Sopenharmony_ci } else { 94570af302Sopenharmony_ci // remove node 95570af302Sopenharmony_ci struct node *next = node->next; 96570af302Sopenharmony_ci if (next) { 97570af302Sopenharmony_ci next->prev = prev; 98570af302Sopenharmony_ci } 99570af302Sopenharmony_ci if (prev) { 100570af302Sopenharmony_ci prev->next = next; 101570af302Sopenharmony_ci } 102570af302Sopenharmony_ci 103570af302Sopenharmony_ci // insert node after tail 104570af302Sopenharmony_ci struct node *tail_next = tail->next; 105570af302Sopenharmony_ci node->prev = tail; 106570af302Sopenharmony_ci node->next = tail_next; 107570af302Sopenharmony_ci tail->next = node; 108570af302Sopenharmony_ci if (tail_next) { 109570af302Sopenharmony_ci tail_next->prev = node; 110570af302Sopenharmony_ci } 111570af302Sopenharmony_ci } 112570af302Sopenharmony_ci 113570af302Sopenharmony_ci g_len--; 114570af302Sopenharmony_ci return prev; 115570af302Sopenharmony_ci} 116570af302Sopenharmony_ci 117570af302Sopenharmony_civoid __funcs_on_exit() 118570af302Sopenharmony_ci{ 119570af302Sopenharmony_ci void (*func)(void *), *arg; 120570af302Sopenharmony_ci 121570af302Sopenharmony_ci LOCK(lock); 122570af302Sopenharmony_ci for (; tail; tail = tail->prev) { 123570af302Sopenharmony_ci func = tail->func; 124570af302Sopenharmony_ci if (func != NULL) { 125570af302Sopenharmony_ci arg = tail->arg; 126570af302Sopenharmony_ci UNLOCK(lock); 127570af302Sopenharmony_ci func(arg); 128570af302Sopenharmony_ci LOCK(lock); 129570af302Sopenharmony_ci } 130570af302Sopenharmony_ci } 131570af302Sopenharmony_ci UNLOCK(lock); 132570af302Sopenharmony_ci} 133570af302Sopenharmony_ci 134570af302Sopenharmony_civoid __cxa_finalize(void *dso) 135570af302Sopenharmony_ci{ 136570af302Sopenharmony_ci void (*func)(void *), *arg; 137570af302Sopenharmony_ci struct node *node; 138570af302Sopenharmony_ci 139570af302Sopenharmony_ci LOCK(lock); 140570af302Sopenharmony_ci for (node = tail; node; ) { 141570af302Sopenharmony_ci if (dso == node->dso) { 142570af302Sopenharmony_ci func = node->func; 143570af302Sopenharmony_ci if (func != NULL) { 144570af302Sopenharmony_ci arg = node->arg; 145570af302Sopenharmony_ci UNLOCK(lock); 146570af302Sopenharmony_ci func(arg); 147570af302Sopenharmony_ci LOCK(lock); 148570af302Sopenharmony_ci } 149570af302Sopenharmony_ci 150570af302Sopenharmony_ci node = RemoveNode(node); 151570af302Sopenharmony_ci continue; 152570af302Sopenharmony_ci } 153570af302Sopenharmony_ci 154570af302Sopenharmony_ci node = node->prev; 155570af302Sopenharmony_ci } 156570af302Sopenharmony_ci 157570af302Sopenharmony_ci UNLOCK(lock); 158570af302Sopenharmony_ci} 159570af302Sopenharmony_ci 160570af302Sopenharmony_cistatic void call(void *p); 161570af302Sopenharmony_ci__attribute__ ((__weak__)) extern void *addr2dso(size_t a); 162570af302Sopenharmony_ci 163570af302Sopenharmony_ciint __cxa_atexit(void (*func)(void *), void *arg, void *dso) 164570af302Sopenharmony_ci{ 165570af302Sopenharmony_ci struct dso *p = NULL; 166570af302Sopenharmony_ci LOCK(lock); 167570af302Sopenharmony_ci 168570af302Sopenharmony_ci#if (defined(FEATURE_ATEXIT_CB_PROTECT)) 169570af302Sopenharmony_ci if ((func == (void *)call) && (dso == NULL)) { 170570af302Sopenharmony_ci if (addr2dso != NULL) { 171570af302Sopenharmony_ci p = addr2dso((size_t)arg); 172570af302Sopenharmony_ci if (p == NULL) { 173570af302Sopenharmony_ci UNLOCK(lock); 174570af302Sopenharmony_ci MUSL_LOGE("call atexit with invalid callback ptr=%{public}p", arg); 175570af302Sopenharmony_ci return -1; 176570af302Sopenharmony_ci } 177570af302Sopenharmony_ci } 178570af302Sopenharmony_ci } 179570af302Sopenharmony_ci#endif 180570af302Sopenharmony_ci 181570af302Sopenharmony_ci if (g_len >= g_capacity) { 182570af302Sopenharmony_ci if (grow()) { 183570af302Sopenharmony_ci UNLOCK(lock); 184570af302Sopenharmony_ci return -1; 185570af302Sopenharmony_ci } 186570af302Sopenharmony_ci } 187570af302Sopenharmony_ci 188570af302Sopenharmony_ci append_node(func, arg, dso, p); 189570af302Sopenharmony_ci 190570af302Sopenharmony_ci UNLOCK(lock); 191570af302Sopenharmony_ci return 0; 192570af302Sopenharmony_ci} 193570af302Sopenharmony_ci 194570af302Sopenharmony_cistatic void call(void *p) 195570af302Sopenharmony_ci{ 196570af302Sopenharmony_ci if (p != NULL) 197570af302Sopenharmony_ci ((void (*)(void))(uintptr_t)p)(); 198570af302Sopenharmony_ci} 199570af302Sopenharmony_ci 200570af302Sopenharmony_ciint atexit(void (*func)(void)) 201570af302Sopenharmony_ci{ 202570af302Sopenharmony_ci return __cxa_atexit(call, (void *)(uintptr_t)func, 0); 203570af302Sopenharmony_ci} 204570af302Sopenharmony_ci 205570af302Sopenharmony_ciint invalidate_exit_funcs(struct dso *p) 206570af302Sopenharmony_ci{ 207570af302Sopenharmony_ci struct node *node; 208570af302Sopenharmony_ci 209570af302Sopenharmony_ci LOCK(lock); 210570af302Sopenharmony_ci for (node = tail; node; node = node->prev) { 211570af302Sopenharmony_ci // if found exit callback relative to this dso, and 212570af302Sopenharmony_ci if (p == node->internal_dso) { 213570af302Sopenharmony_ci if ((node->dso == NULL) && node->func == (void *)call) { 214570af302Sopenharmony_ci MUSL_LOGD("invalidate callback ptr=%{public}p when uninstall %{public}s", node->arg, p->name); 215570af302Sopenharmony_ci node->arg = NULL; 216570af302Sopenharmony_ci } 217570af302Sopenharmony_ci } 218570af302Sopenharmony_ci } 219570af302Sopenharmony_ci UNLOCK(lock); 220570af302Sopenharmony_ci 221570af302Sopenharmony_ci return 0; 222570af302Sopenharmony_ci}