Changeset 9a41e6e in mainline
- Timestamp:
- 2025-03-05T22:54:36Z (4 days ago)
- Children:
- 7064e71
- Parents:
- 2482192
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/posix/src/pthread/keys.c
r2482192 r9a41e6e 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) return NULL; 61 62 assert(key < PTHREAD_KEYS_MAX); 63 assert(key < next_key); 64 assert(key > 0); 65 66 return key_data[key]; 67 } 68 69 static void pthread_key_on_fibril_exit(void) { 70 if (!fibril_initialized) return; 71 72 for (unsigned i = 0; i < PTHREAD_KEYS_MAX; i++) { 73 /* 74 * Note that this doesn't cause a race with pthread_key_create: 75 * if key `i` has not been assigned yet (it could be just being 76 * created), key_data[i] has never been assigned, therefore it 77 * is NULL, and the destructor is not checked at all. 78 */ 79 if (key_data[i] != NULL && destructors[i] != NULL) 80 destructors[i](key_data[i]); 81 } 44 82 } 45 83 46 84 int pthread_setspecific(pthread_key_t key, const void *data) 47 85 { 48 not_implemented(); 49 return ENOTSUP; 86 if (!fibril_initialized) { 87 DPRINTF("initializing pthread keys\n"); 88 errno_t res = fibril_add_exit_hook(pthread_key_on_fibril_exit); 89 if (res != EOK) return res; 90 for (unsigned i = 0; i < PTHREAD_KEYS_MAX; i++) { 91 key_data[i] = NULL; 92 } 93 fibril_initialized = true; 94 } 95 assert(key < PTHREAD_KEYS_MAX); 96 assert(key < next_key); 97 assert(key > 0); 98 99 key_data[key] = (void *) data; 100 return EOK; 50 101 } 51 102 52 103 int pthread_key_delete(pthread_key_t key) 53 104 { 54 not_implemented(); 55 return ENOTSUP; 105 /* 106 * FIXME: this can cause a data race with another fibrill 107 * running on_fibril_exit. The obvious solution is to add 108 * a rwlock on the destructors array, which will be needed 109 * anyway if we want to support unlimited number of keys. 110 */ 111 destructors[key] = NULL; 112 key_data[key] = NULL; 113 114 // TODO: the key could also be reused 115 return EOK; 56 116 } 57 117 58 118 int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) 59 119 { 60 not_implemented(); 61 return ENOTSUP; 120 unsigned short k = atomic_fetch_add(&next_key, 1); 121 if (k >= PTHREAD_KEYS_MAX) { 122 atomic_store(&next_key, PTHREAD_KEYS_MAX + 1); 123 return ELIMIT; 124 } 125 126 destructors[k] = destructor; 127 *key = k; 128 return EOK; 62 129 } 63 130
Note:
See TracChangeset
for help on using the changeset viewer.