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