Changeset 88cbc66 in mainline
- Timestamp:
- 2025-03-08T16:41:12Z (22 hours ago)
- Parents:
- 797ab95 (diff), af28af6 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - git-author:
- Matěj Volf <mat.volfik@…> (2025-03-08 16:41:12)
- git-committer:
- GitHub <noreply@…> (2025-03-08 16:41:12)
- Location:
- uspace/lib
- Files:
-
- 2 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/libc.c
r797ab95 r88cbc66 81 81 main_fibril.tcb = tls_make_initial(__progsymbols.elfstart); 82 82 } 83 main_fibril.is_freeable = false; 83 84 84 85 assert(main_fibril.tcb); … … 172 173 void __libc_exit(int status) 173 174 { 175 fibril_run_exit_hooks(&main_fibril); 176 174 177 /* 175 178 * GCC extension __attribute__((destructor)), -
uspace/lib/c/generic/private/fibril.h
r797ab95 r88cbc66 70 70 fibril_owner_info_t *waits_for; 71 71 fibril_event_t *sleep_event; 72 73 list_t exit_hooks; 72 74 }; 75 76 typedef struct { 77 link_t link; 78 void (*func)(void); 79 } fibril_hook_t; 73 80 74 81 extern fibril_t *fibril_alloc(void); … … 86 93 extern errno_t fibril_ipc_wait(ipc_call_t *, const struct timespec *); 87 94 extern void fibril_ipc_poke(void); 95 96 extern void fibril_run_exit_hooks(fibril_t *); 88 97 89 98 /** -
uspace/lib/c/generic/rtld/symbol.c
r797ab95 r88cbc66 65 65 static elf_symbol_t *def_find_in_module(const char *name, module_t *m) 66 66 { 67 if (m->dyn.hash == NULL) { 68 /* No hash table */ 69 return NULL; 70 } 71 67 72 elf_symbol_t *sym_table; 68 73 elf_symbol_t *s, *sym; -
uspace/lib/c/generic/thread/fibril.c
r797ab95 r88cbc66 185 185 void fibril_setup(fibril_t *f) 186 186 { 187 list_initialize(&f->exit_hooks); 187 188 futex_lock(&fibril_futex); 188 189 list_append(&f->all_link, &fibril_list); … … 845 846 } 846 847 848 void fibril_run_exit_hooks(fibril_t *f) 849 { 850 list_foreach_safe(f->exit_hooks, cur, _next) { 851 fibril_hook_t *hook = list_get_instance(cur, fibril_hook_t, link); 852 list_remove(cur); 853 hook->func(); 854 free(hook); 855 } 856 } 857 847 858 /** 848 859 * Exit a fibril. Never returns. … … 854 865 // TODO: implement fibril_join() and remember retval 855 866 (void) retval; 867 868 fibril_run_exit_hooks(fibril_self()); 856 869 857 870 fibril_t *f = _ready_list_pop_nonblocking(false); … … 918 931 } 919 932 933 errno_t fibril_add_exit_hook(void (*hook)(void)) 934 { 935 fibril_hook_t *h = malloc(sizeof(fibril_hook_t)); 936 if (!h) 937 return ENOMEM; 938 939 DPRINTF("adding exit hook: function %p (fibril_hook_t structure at %p)\n", hook, h); 940 941 h->func = hook; 942 list_append(&h->link, &fibril_self()->exit_hooks); 943 return EOK; 944 } 945 920 946 errno_t fibril_ipc_wait(ipc_call_t *call, const struct timespec *expires) 921 947 { -
uspace/lib/c/include/fibril.h
r797ab95 r88cbc66 74 74 extern __noreturn void fibril_exit(long); 75 75 76 /** Add a function to be called after fibril exits, just before it is destroyed */ 77 extern errno_t fibril_add_exit_hook(void (*)(void)); 78 76 79 __HELENOS_DECLS_END; 77 80 -
uspace/lib/c/meson.build
r797ab95 r88cbc66 177 177 'test/double_to_str.c', 178 178 'test/fibril/timer.c', 179 'test/fibril/exit_hook.c', 179 180 'test/getopt.c', 180 181 'test/gsort.c', -
uspace/lib/c/test/main.c
r797ab95 r88cbc66 38 38 PCUT_IMPORT(double_to_str); 39 39 PCUT_IMPORT(fibril_timer); 40 PCUT_IMPORT(fibril_exit_hook); 40 41 PCUT_IMPORT(getopt); 41 42 PCUT_IMPORT(gsort); -
uspace/lib/posix/meson.build
r797ab95 r88cbc66 61 61 'test/stdlib.c', 62 62 'test/unistd.c', 63 'test/pthread/keys.c', 63 64 ) 64 65 -
uspace/lib/posix/src/pthread/keys.c
r797ab95 r88cbc66 36 36 #include <pthread.h> 37 37 #include <errno.h> 38 #include <fibril.h> 39 #include <stdatomic.h> 38 40 #include "../internal/common.h" 41 42 #define DPRINTF(format, ...) ((void) 0) 43 44 static fibril_local bool fibril_initialized = false; 45 static atomic_ushort next_key = 1; // skip the key 'zero' 46 47 /* 48 * For now, we just support maximum of 100 keys. This can be improved 49 * in the future by implementing a dynamically growing array with 50 * reallocations, but that will require more synchronization. 51 */ 52 #define PTHREAD_KEYS_MAX 100 53 static void (*destructors[PTHREAD_KEYS_MAX])(void *); 54 55 static fibril_local void *key_data[PTHREAD_KEYS_MAX]; 39 56 40 57 void *pthread_getspecific(pthread_key_t key) 41 58 { 42 not_implemented(); 43 return NULL; 59 // initialization is done in setspecific -> if not initialized, nothing was set yet 60 if (!fibril_initialized) 61 return NULL; 62 63 assert(key < PTHREAD_KEYS_MAX); 64 assert(key < next_key); 65 assert(key > 0); 66 67 return key_data[key]; 68 } 69 70 static void pthread_key_on_fibril_exit(void) 71 { 72 if (!fibril_initialized) 73 return; 74 75 for (unsigned i = 0; i < PTHREAD_KEYS_MAX; i++) { 76 /* 77 * Note that this doesn't cause a race with pthread_key_create: 78 * if key `i` has not been assigned yet (it could be just being 79 * created), key_data[i] has never been assigned, therefore it 80 * is NULL, and the destructor is not checked at all. 81 */ 82 if (key_data[i] != NULL && destructors[i] != NULL) 83 destructors[i](key_data[i]); 84 } 44 85 } 45 86 46 87 int pthread_setspecific(pthread_key_t key, const void *data) 47 88 { 48 not_implemented(); 49 return ENOTSUP; 89 if (!fibril_initialized) { 90 DPRINTF("initializing pthread keys\n"); 91 errno_t res = fibril_add_exit_hook(pthread_key_on_fibril_exit); 92 if (res != EOK) 93 return res; 94 95 for (unsigned i = 0; i < PTHREAD_KEYS_MAX; i++) { 96 key_data[i] = NULL; 97 } 98 fibril_initialized = true; 99 } 100 assert(key < PTHREAD_KEYS_MAX); 101 assert(key < next_key); 102 assert(key > 0); 103 104 key_data[key] = (void *) data; 105 return EOK; 50 106 } 51 107 52 108 int pthread_key_delete(pthread_key_t key) 53 109 { 54 not_implemented(); 55 return ENOTSUP; 110 /* 111 * FIXME: this can cause a data race if another fibrill concurrently 112 * runs on_fibril_exit. The obvious solution is to add a rwlock on 113 * the destructors array, which will be needed anyway if we want to 114 * support unlimited number of keys. 115 */ 116 destructors[key] = NULL; 117 key_data[key] = NULL; 118 119 // TODO: the key could also be reused 120 return EOK; 56 121 } 57 122 58 123 int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) 59 124 { 60 not_implemented(); 61 return ENOTSUP; 125 unsigned short k = atomic_fetch_add(&next_key, 1); 126 if (k >= PTHREAD_KEYS_MAX) { 127 atomic_store(&next_key, PTHREAD_KEYS_MAX + 1); 128 return ELIMIT; 129 } 130 131 destructors[k] = destructor; 132 *key = k; 133 return EOK; 62 134 } 63 135 -
uspace/lib/posix/test/main.c
r797ab95 r88cbc66 34 34 PCUT_IMPORT(stdlib); 35 35 PCUT_IMPORT(unistd); 36 PCUT_IMPORT(pthread_keys); 36 37 37 38 PCUT_MAIN();
Note:
See TracChangeset
for help on using the changeset viewer.