Changeset d50f3e5 in mainline
- Timestamp:
- 2025-03-09T20:06:24Z (12 hours ago)
- Children:
- 53e652d
- Parents:
- af28af6
- git-author:
- Matěj Volf <git@…> (2025-03-09 20:05:51)
- git-committer:
- Matěj Volf <git@…> (2025-03-09 20:06:24)
- Location:
- uspace/lib
- Files:
-
- 1 deleted
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/libc.c
raf28af6 rd50f3e5 173 173 void __libc_exit(int status) 174 174 { 175 fibril_run_exit_hooks(&main_fibril);176 177 175 /* 178 176 * GCC extension __attribute__((destructor)), -
uspace/lib/c/generic/private/fibril.h
raf28af6 rd50f3e5 70 70 fibril_owner_info_t *waits_for; 71 71 fibril_event_t *sleep_event; 72 73 list_t exit_hooks;74 72 }; 75 76 typedef struct {77 link_t link;78 void (*func)(void);79 } fibril_hook_t;80 73 81 74 extern fibril_t *fibril_alloc(void); … … 93 86 extern errno_t fibril_ipc_wait(ipc_call_t *, const struct timespec *); 94 87 extern void fibril_ipc_poke(void); 95 96 extern void fibril_run_exit_hooks(fibril_t *);97 88 98 89 /** -
uspace/lib/c/generic/thread/fibril.c
raf28af6 rd50f3e5 185 185 void fibril_setup(fibril_t *f) 186 186 { 187 list_initialize(&f->exit_hooks);188 187 futex_lock(&fibril_futex); 189 188 list_append(&f->all_link, &fibril_list); … … 846 845 } 847 846 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 858 847 /** 859 848 * Exit a fibril. Never returns. … … 865 854 // TODO: implement fibril_join() and remember retval 866 855 (void) retval; 867 868 fibril_run_exit_hooks(fibril_self());869 856 870 857 fibril_t *f = _ready_list_pop_nonblocking(false); … … 931 918 } 932 919 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 946 920 errno_t fibril_ipc_wait(ipc_call_t *call, const struct timespec *expires) 947 921 { -
uspace/lib/c/include/fibril.h
raf28af6 rd50f3e5 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 79 76 __HELENOS_DECLS_END; 80 77 -
uspace/lib/c/meson.build
raf28af6 rd50f3e5 177 177 'test/double_to_str.c', 178 178 'test/fibril/timer.c', 179 'test/fibril/exit_hook.c',180 179 'test/getopt.c', 181 180 'test/gsort.c', -
uspace/lib/c/test/main.c
raf28af6 rd50f3e5 38 38 PCUT_IMPORT(double_to_str); 39 39 PCUT_IMPORT(fibril_timer); 40 PCUT_IMPORT(fibril_exit_hook);41 40 PCUT_IMPORT(getopt); 42 41 PCUT_IMPORT(gsort); -
uspace/lib/posix/src/pthread/keys.c
raf28af6 rd50f3e5 40 40 #include "../internal/common.h" 41 41 42 #define DPRINTF(format, ...) ((void) 0) 42 #include <stdio.h> 43 #define DPRINTF(format, ...) printf("pthread_keys: " format, ##__VA_ARGS__) 43 44 44 45 static fibril_local bool fibril_initialized = false; … … 51 52 */ 52 53 #define PTHREAD_KEYS_MAX 100 53 static void (*destructors[PTHREAD_KEYS_MAX])(void *);54 54 55 55 static fibril_local void *key_data[PTHREAD_KEYS_MAX]; … … 58 58 { 59 59 // initialization is done in setspecific -> if not initialized, nothing was set yet 60 if (!fibril_initialized) 60 if (!fibril_initialized) { 61 DPRINTF("pthread_getspecific(%d) = NULL (uninitialized)\n", key); 61 62 return NULL; 63 } 62 64 63 65 assert(key < PTHREAD_KEYS_MAX); … … 65 67 assert(key > 0); 66 68 69 DPRINTF("pthread_getspecific(%d) = %p\n", key, key_data[key]); 67 70 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 being79 * created), key_data[i] has never been assigned, therefore it80 * 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 }85 71 } 86 72 87 73 int pthread_setspecific(pthread_key_t key, const void *data) 88 74 { 75 DPRINTF("pthread_setspecific(%d, %p)\n", key, data); 89 76 if (!fibril_initialized) { 90 77 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 78 for (unsigned i = 0; i < PTHREAD_KEYS_MAX; i++) { 96 79 key_data[i] = NULL; … … 108 91 int pthread_key_delete(pthread_key_t key) 109 92 { 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 93 // see https://github.com/HelenOS/helenos/pull/245#issuecomment-2706795848 94 not_implemented(); 120 95 return EOK; 121 96 } … … 124 99 { 125 100 unsigned short k = atomic_fetch_add(&next_key, 1); 101 DPRINTF("pthread_key_create(%p, %p) = %d\n", key, destructor, k); 126 102 if (k >= PTHREAD_KEYS_MAX) { 127 103 atomic_store(&next_key, PTHREAD_KEYS_MAX + 1); 128 104 return ELIMIT; 129 105 } 106 if (destructor != NULL) { 107 static int __counter = 0; 108 if (__counter == 0) { 109 fprintf(stderr, "pthread_key_create: destructors not supported\n"); 110 } 111 __counter++; 112 } 130 113 131 destructors[k] = destructor;132 114 *key = k; 133 115 return EOK; -
uspace/lib/posix/test/pthread/keys.c
raf28af6 rd50f3e5 36 36 37 37 pthread_key_t key; 38 int destructors_executed;39 40 static void destructor(void *_data)41 {42 destructors_executed++;43 }44 38 45 39 static errno_t simple_fibril(void *_arg) … … 57 51 PCUT_TEST(pthread_keys_basic) 58 52 { 59 destructors_executed = 0; 60 PCUT_ASSERT_INT_EQUALS(0, pthread_key_create(&key, destructor)); 53 PCUT_ASSERT_INT_EQUALS(0, pthread_key_create(&key, NULL)); 61 54 PCUT_ASSERT_PTR_EQUALS(NULL, pthread_getspecific(key)); 62 55 … … 71 64 } 72 65 73 PCUT_ASSERT_INT_EQUALS(0, destructors_executed);74 66 PCUT_ASSERT_PTR_EQUALS((void *) 0x42, pthread_getspecific(key)); 75 67 … … 78 70 } 79 71 80 PCUT_ASSERT_INT_EQUALS(1, destructors_executed);81 72 PCUT_ASSERT_PTR_EQUALS((void *) 0x42, pthread_getspecific(key)); 82 73 }
Note:
See TracChangeset
for help on using the changeset viewer.