1 #include <minix/mthread.h> 2 #include <string.h> 3 #include "global.h" 4 #include "proto.h" 5 6 static int keys_used = 0; 7 static struct { 8 int used; 9 int nvalues; 10 void *mvalue; 11 void **value; 12 void (*destr)(void *); 13 } keys[MTHREAD_KEYS_MAX]; 14 15 /*===========================================================================* 16 * mthread_init_keys * 17 *===========================================================================*/ 18 void mthread_init_keys(void) 19 { 20 /* Initialize the table of key entries. 21 */ 22 mthread_key_t k; 23 24 for (k = 0; k < MTHREAD_KEYS_MAX; k++) 25 keys[k].used = FALSE; 26 } 27 28 /*===========================================================================* 29 * mthread_key_create * 30 *===========================================================================*/ 31 int mthread_key_create(mthread_key_t *key, void (*destructor)(void *)) 32 { 33 /* Allocate a key. 34 */ 35 mthread_key_t k; 36 37 keys_used = 1; 38 39 /* We do not yet allocate storage space for the values here, because we can 40 * not estimate how many threads will be created in the common case that the 41 * application creates keys before spawning threads. 42 */ 43 for (k = 0; k < MTHREAD_KEYS_MAX; k++) { 44 if (!keys[k].used) { 45 keys[k].used = TRUE; 46 keys[k].nvalues = 0; 47 keys[k].mvalue = NULL; 48 keys[k].value = NULL; 49 keys[k].destr = destructor; 50 *key = k; 51 52 return(0); 53 } 54 } 55 56 return(EAGAIN); 57 } 58 59 /*===========================================================================* 60 * mthread_key_delete * 61 *===========================================================================*/ 62 int mthread_key_delete(mthread_key_t key) 63 { 64 /* Free up a key, as well as any associated storage space. 65 */ 66 67 if (key < 0 || key >= MTHREAD_KEYS_MAX || !keys[key].used) 68 return(EINVAL); 69 70 free(keys[key].value); 71 72 keys[key].used = FALSE; 73 74 return(0); 75 } 76 77 /*===========================================================================* 78 * mthread_getspecific * 79 *===========================================================================*/ 80 void *mthread_getspecific(mthread_key_t key) 81 { 82 /* Get this thread's local value for the given key. The default is NULL. 83 */ 84 85 if (key < 0 || key >= MTHREAD_KEYS_MAX || !keys[key].used) 86 return(NULL); 87 88 if (current_thread == MAIN_THREAD) 89 return keys[key].mvalue; 90 91 if (current_thread < keys[key].nvalues) 92 return(keys[key].value[current_thread]); 93 94 return(NULL); 95 } 96 97 /*===========================================================================* 98 * mthread_setspecific * 99 *===========================================================================*/ 100 int mthread_setspecific(mthread_key_t key, void *value) 101 { 102 /* Set this thread's value for the given key. Allocate more resources as 103 * necessary. 104 */ 105 void **p; 106 107 if (key < 0 || key >= MTHREAD_KEYS_MAX || !keys[key].used) 108 return(EINVAL); 109 110 if (current_thread == MAIN_THREAD) { 111 keys[key].mvalue = value; 112 113 return(0); 114 } 115 116 if (current_thread >= keys[key].nvalues) { 117 if (current_thread >= no_threads) 118 mthread_panic("Library state corrupt"); 119 120 if ((p = (void **) realloc(keys[key].value, 121 sizeof(void*) * no_threads)) == NULL) 122 return(ENOMEM); 123 124 memset(&p[keys[key].nvalues], 0, 125 sizeof(void*) * (no_threads - keys[key].nvalues)); 126 127 keys[key].nvalues = no_threads; 128 keys[key].value = p; 129 } 130 131 keys[key].value[current_thread] = value; 132 133 return(0); 134 } 135 136 /*===========================================================================* 137 * mthread_cleanup_values * 138 *===========================================================================*/ 139 void mthread_cleanup_values(void) 140 { 141 /* Clean up all the values associated with an exiting thread, calling keys' 142 * destruction procedures as appropriate. 143 */ 144 mthread_key_t k; 145 void *value; 146 int found; 147 148 if (!keys_used) return; /* Only clean up if we used any keys at all */ 149 150 /* Any of the destructors may set a new value on any key, so we may have to 151 * loop over the table of keys multiple times. This implementation has no 152 * protection against infinite loops in this case. 153 */ 154 do { 155 found = FALSE; 156 157 for (k = 0; k < MTHREAD_KEYS_MAX; k++) { 158 if (!keys[k].used) continue; 159 if (keys[k].destr == NULL) continue; 160 161 if (current_thread == MAIN_THREAD) { 162 value = keys[k].mvalue; 163 164 keys[k].mvalue = NULL; 165 } else { 166 if (current_thread >= keys[k].nvalues) continue; 167 168 value = keys[k].value[current_thread]; 169 170 keys[k].value[current_thread] = NULL; 171 } 172 173 if (value != NULL) { 174 /* Note: calling mthread_exit() from a destructor 175 * causes undefined behavior. 176 */ 177 keys[k].destr(value); 178 179 found = TRUE; 180 } 181 } 182 } while (found); 183 } 184 185 /* pthread compatibility layer. */ 186 __weak_alias(pthread_key_create, mthread_key_create) 187 __weak_alias(pthread_key_delete, mthread_key_delete) 188 __weak_alias(pthread_getspecific, mthread_getspecific) 189 __weak_alias(pthread_setspecific, mthread_setspecific) 190 191