ldivmod, uldivmod: fix qdivrem calls
[minix.git] / lib / libmthread / key.c
blobf07b26f45fb9911f802164edeac937341b5e3339
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 MTHREAD_CHECK_INIT(); /* Make sure libmthread is initialized */
38 keys_used = 1;
40 /* We do not yet allocate storage space for the values here, because we can
41 * not estimate how many threads will be created in the common case that the
42 * application creates keys before spawning threads.
44 for (k = 0; k < MTHREAD_KEYS_MAX; k++) {
45 if (!keys[k].used) {
46 keys[k].used = TRUE;
47 keys[k].nvalues = 0;
48 keys[k].mvalue = NULL;
49 keys[k].value = NULL;
50 keys[k].destr = destructor;
51 *key = k;
53 return(0);
57 return(EAGAIN);
60 /*===========================================================================*
61 * mthread_key_delete *
62 *===========================================================================*/
63 int mthread_key_delete(mthread_key_t key)
65 /* Free up a key, as well as any associated storage space.
68 MTHREAD_CHECK_INIT(); /* Make sure libmthread is initialized */
70 if (key < 0 || key >= MTHREAD_KEYS_MAX || !keys[key].used)
71 return(EINVAL);
73 free(keys[key].value);
75 keys[key].used = FALSE;
77 return(0);
80 /*===========================================================================*
81 * mthread_getspecific *
82 *===========================================================================*/
83 void *mthread_getspecific(mthread_key_t key)
85 /* Get this thread's local value for the given key. The default is NULL.
88 MTHREAD_CHECK_INIT(); /* Make sure libmthread is initialized */
90 if (key < 0 || key >= MTHREAD_KEYS_MAX || !keys[key].used)
91 return(NULL);
93 if (current_thread == MAIN_THREAD)
94 return keys[key].mvalue;
96 if (current_thread < keys[key].nvalues)
97 return(keys[key].value[current_thread]);
99 return(NULL);
102 /*===========================================================================*
103 * mthread_setspecific *
104 *===========================================================================*/
105 int mthread_setspecific(mthread_key_t key, void *value)
107 /* Set this thread's value for the given key. Allocate more resources as
108 * necessary.
110 void **p;
112 MTHREAD_CHECK_INIT(); /* Make sure libmthread is initialized */
114 if (key < 0 || key >= MTHREAD_KEYS_MAX || !keys[key].used)
115 return(EINVAL);
117 if (current_thread == MAIN_THREAD) {
118 keys[key].mvalue = value;
120 return(0);
123 if (current_thread >= keys[key].nvalues) {
124 if (current_thread >= no_threads)
125 mthread_panic("Library state corrupt");
127 if ((p = (void **) realloc(keys[key].value,
128 sizeof(void*) * no_threads)) == NULL)
129 return(ENOMEM);
131 memset(&p[keys[key].nvalues], 0,
132 sizeof(void*) * (no_threads - keys[key].nvalues));
134 keys[key].nvalues = no_threads;
135 keys[key].value = p;
138 keys[key].value[current_thread] = value;
140 return(0);
143 /*===========================================================================*
144 * mthread_cleanup_values *
145 *===========================================================================*/
146 void mthread_cleanup_values(void)
148 /* Clean up all the values associated with an exiting thread, calling keys'
149 * destruction procedures as appropriate.
151 mthread_key_t k;
152 void *value;
153 int found;
155 if (!keys_used) return; /* Only clean up if we used any keys at all */
157 /* Any of the destructors may set a new value on any key, so we may have to
158 * loop over the table of keys multiple times. This implementation has no
159 * protection against infinite loops in this case.
161 do {
162 found = FALSE;
164 for (k = 0; k < MTHREAD_KEYS_MAX; k++) {
165 if (!keys[k].used) continue;
166 if (keys[k].destr == NULL) continue;
168 if (current_thread == MAIN_THREAD) {
169 value = keys[k].mvalue;
171 keys[k].mvalue = NULL;
172 } else {
173 if (current_thread >= keys[k].nvalues) continue;
175 value = keys[k].value[current_thread];
177 keys[k].value[current_thread] = NULL;
180 if (value != NULL) {
181 /* Note: calling mthread_exit() from a destructor
182 * causes undefined behavior.
184 keys[k].destr(value);
186 found = TRUE;
189 } while (found);