xref: /minix3/minix/lib/libmthread/key.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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