Remove building with NOCRYPTO option
[minix.git] / minix / lib / libmthread / key.c
blobcfb3b55f246d701c347be37aa8f5af090c6274ef
1 #include <minix/mthread.h>
2 #include <string.h>
3 #include "global.h"
4 #include "proto.h"
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];
15 /*===========================================================================*
16 * mthread_init_keys *
17 *===========================================================================*/
18 void mthread_init_keys(void)
20 /* Initialize the table of key entries.
22 mthread_key_t k;
24 for (k = 0; k < MTHREAD_KEYS_MAX; k++)
25 keys[k].used = FALSE;
28 /*===========================================================================*
29 * mthread_key_create *
30 *===========================================================================*/
31 int mthread_key_create(mthread_key_t *key, void (*destructor)(void *))
33 /* Allocate a key.
35 mthread_key_t k;
37 keys_used = 1;
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.
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;
52 return(0);
56 return(EAGAIN);
59 /*===========================================================================*
60 * mthread_key_delete *
61 *===========================================================================*/
62 int mthread_key_delete(mthread_key_t key)
64 /* Free up a key, as well as any associated storage space.
67 if (key < 0 || key >= MTHREAD_KEYS_MAX || !keys[key].used)
68 return(EINVAL);
70 free(keys[key].value);
72 keys[key].used = FALSE;
74 return(0);
77 /*===========================================================================*
78 * mthread_getspecific *
79 *===========================================================================*/
80 void *mthread_getspecific(mthread_key_t key)
82 /* Get this thread's local value for the given key. The default is NULL.
85 if (key < 0 || key >= MTHREAD_KEYS_MAX || !keys[key].used)
86 return(NULL);
88 if (current_thread == MAIN_THREAD)
89 return keys[key].mvalue;
91 if (current_thread < keys[key].nvalues)
92 return(keys[key].value[current_thread]);
94 return(NULL);
97 /*===========================================================================*
98 * mthread_setspecific *
99 *===========================================================================*/
100 int mthread_setspecific(mthread_key_t key, void *value)
102 /* Set this thread's value for the given key. Allocate more resources as
103 * necessary.
105 void **p;
107 if (key < 0 || key >= MTHREAD_KEYS_MAX || !keys[key].used)
108 return(EINVAL);
110 if (current_thread == MAIN_THREAD) {
111 keys[key].mvalue = value;
113 return(0);
116 if (current_thread >= keys[key].nvalues) {
117 if (current_thread >= no_threads)
118 mthread_panic("Library state corrupt");
120 if ((p = (void **) realloc(keys[key].value,
121 sizeof(void*) * no_threads)) == NULL)
122 return(ENOMEM);
124 memset(&p[keys[key].nvalues], 0,
125 sizeof(void*) * (no_threads - keys[key].nvalues));
127 keys[key].nvalues = no_threads;
128 keys[key].value = p;
131 keys[key].value[current_thread] = value;
133 return(0);
136 /*===========================================================================*
137 * mthread_cleanup_values *
138 *===========================================================================*/
139 void mthread_cleanup_values(void)
141 /* Clean up all the values associated with an exiting thread, calling keys'
142 * destruction procedures as appropriate.
144 mthread_key_t k;
145 void *value;
146 int found;
148 if (!keys_used) return; /* Only clean up if we used any keys at all */
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.
154 do {
155 found = FALSE;
157 for (k = 0; k < MTHREAD_KEYS_MAX; k++) {
158 if (!keys[k].used) continue;
159 if (keys[k].destr == NULL) continue;
161 if (current_thread == MAIN_THREAD) {
162 value = keys[k].mvalue;
164 keys[k].mvalue = NULL;
165 } else {
166 if (current_thread >= keys[k].nvalues) continue;
168 value = keys[k].value[current_thread];
170 keys[k].value[current_thread] = NULL;
173 if (value != NULL) {
174 /* Note: calling mthread_exit() from a destructor
175 * causes undefined behavior.
177 keys[k].destr(value);
179 found = TRUE;
182 } while (found);
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)