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 *===========================================================================*/
mthread_init_keys(void)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 *===========================================================================*/
mthread_key_create(mthread_key_t * key,void (* destructor)(void *))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 *===========================================================================*/
mthread_key_delete(mthread_key_t key)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 *===========================================================================*/
mthread_getspecific(mthread_key_t key)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 *===========================================================================*/
mthread_setspecific(mthread_key_t key,void * value)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 *===========================================================================*/
mthread_cleanup_values(void)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