 76092ddf33
			
		
	
	
		76092ddf33
		
	
	
	
	
		
			
			This can be turned back on when the library is compiled with -DMTHREAD_STRICT (which enables more sanity checks). However, always performing this check shows up in system profiling results.
		
			
				
	
	
		
			191 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <minix/mthread.h>
 | |
| #include <string.h>
 | |
| #include "global.h"
 | |
| #include "proto.h"
 | |
| 
 | |
| static int keys_used = 0;
 | |
| static struct {
 | |
|   int used;
 | |
|   int nvalues;
 | |
|   void *mvalue;
 | |
|   void **value;
 | |
|   void (*destr)(void *);
 | |
| } keys[MTHREAD_KEYS_MAX];
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_init_keys			     *
 | |
|  *===========================================================================*/
 | |
| void mthread_init_keys(void)
 | |
| {
 | |
| /* Initialize the table of key entries.
 | |
|  */
 | |
|   mthread_key_t k;
 | |
| 
 | |
|   for (k = 0; k < MTHREAD_KEYS_MAX; k++)
 | |
| 	keys[k].used = FALSE;
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_key_create			     *
 | |
|  *===========================================================================*/
 | |
| int mthread_key_create(mthread_key_t *key, void (*destructor)(void *))
 | |
| {
 | |
| /* Allocate a key.
 | |
|  */
 | |
|   mthread_key_t k;
 | |
| 
 | |
|   MTHREAD_CHECK_INIT();	/* Make sure libmthread is initialized */
 | |
|   keys_used = 1;
 | |
| 
 | |
|   /* We do not yet allocate storage space for the values here, because we can
 | |
|    * not estimate how many threads will be created in the common case that the
 | |
|    * application creates keys before spawning threads.
 | |
|    */
 | |
|   for (k = 0; k < MTHREAD_KEYS_MAX; k++) {
 | |
| 	if (!keys[k].used) {
 | |
| 		keys[k].used = TRUE;
 | |
| 		keys[k].nvalues = 0;
 | |
| 		keys[k].mvalue = NULL;
 | |
| 		keys[k].value = NULL;
 | |
| 		keys[k].destr = destructor;
 | |
| 		*key = k;
 | |
| 
 | |
| 		return(0);
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   return(EAGAIN);
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_key_delete			     *
 | |
|  *===========================================================================*/
 | |
| int mthread_key_delete(mthread_key_t key)
 | |
| {
 | |
| /* Free up a key, as well as any associated storage space.
 | |
|  */
 | |
| 
 | |
|   MTHREAD_CHECK_INIT();	/* Make sure libmthread is initialized */
 | |
| 
 | |
|   if (key < 0 || key >= MTHREAD_KEYS_MAX || !keys[key].used)
 | |
| 	return(EINVAL);
 | |
| 
 | |
|   free(keys[key].value);
 | |
| 
 | |
|   keys[key].used = FALSE;
 | |
| 
 | |
|   return(0);
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_getspecific			     *
 | |
|  *===========================================================================*/
 | |
| void *mthread_getspecific(mthread_key_t key)
 | |
| {
 | |
| /* Get this thread's local value for the given key. The default is NULL.
 | |
|  */
 | |
| 
 | |
|   MTHREAD_CHECK_INIT();	/* Make sure libmthread is initialized */
 | |
| 
 | |
|   if (key < 0 || key >= MTHREAD_KEYS_MAX || !keys[key].used)
 | |
| 	return(NULL);
 | |
| 
 | |
|   if (current_thread == MAIN_THREAD)
 | |
| 	return keys[key].mvalue;
 | |
| 
 | |
|   if (current_thread < keys[key].nvalues)
 | |
| 	return(keys[key].value[current_thread]);
 | |
| 
 | |
|   return(NULL);
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_setspecific			     *
 | |
|  *===========================================================================*/
 | |
| int mthread_setspecific(mthread_key_t key, void *value)
 | |
| {
 | |
| /* Set this thread's value for the given key. Allocate more resources as
 | |
|  * necessary.
 | |
|  */
 | |
|   void **p;
 | |
| 
 | |
|   MTHREAD_CHECK_INIT();	/* Make sure libmthread is initialized */
 | |
| 
 | |
|   if (key < 0 || key >= MTHREAD_KEYS_MAX || !keys[key].used)
 | |
| 	return(EINVAL);
 | |
| 
 | |
|   if (current_thread == MAIN_THREAD) {
 | |
| 	keys[key].mvalue = value;
 | |
| 
 | |
| 	return(0);
 | |
|   }
 | |
| 
 | |
|   if (current_thread >= keys[key].nvalues) {
 | |
| 	if (current_thread >= no_threads)
 | |
| 		mthread_panic("Library state corrupt");
 | |
| 
 | |
| 	if ((p = (void **) realloc(keys[key].value,
 | |
| 			sizeof(void*) * no_threads)) == NULL)
 | |
| 		return(ENOMEM);
 | |
| 
 | |
| 	memset(&p[keys[key].nvalues], 0,
 | |
| 		sizeof(void*) * (no_threads - keys[key].nvalues));
 | |
| 
 | |
| 	keys[key].nvalues = no_threads;
 | |
| 	keys[key].value = p;
 | |
|   }
 | |
| 
 | |
|   keys[key].value[current_thread] = value;
 | |
| 
 | |
|   return(0);
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_cleanup_values			     *
 | |
|  *===========================================================================*/
 | |
| void mthread_cleanup_values(void)
 | |
| {
 | |
| /* Clean up all the values associated with an exiting thread, calling keys'
 | |
|  * destruction procedures as appropriate.
 | |
|  */
 | |
|   mthread_key_t k;
 | |
|   void *value;
 | |
|   int found;
 | |
| 
 | |
|   if (!keys_used) return;	/* Only clean up if we used any keys at all */
 | |
| 
 | |
|   /* Any of the destructors may set a new value on any key, so we may have to
 | |
|    * loop over the table of keys multiple times. This implementation has no
 | |
|    * protection against infinite loops in this case.
 | |
|    */
 | |
|   do {
 | |
| 	found = FALSE;
 | |
| 
 | |
| 	for (k = 0; k < MTHREAD_KEYS_MAX; k++) {
 | |
| 		if (!keys[k].used) continue;
 | |
| 		if (keys[k].destr == NULL) continue;
 | |
| 
 | |
| 		if (current_thread == MAIN_THREAD) {
 | |
| 			value = keys[k].mvalue;
 | |
| 
 | |
| 			keys[k].mvalue = NULL;
 | |
| 		} else {
 | |
| 			if (current_thread >= keys[k].nvalues) continue;
 | |
| 
 | |
| 			value = keys[k].value[current_thread];
 | |
| 
 | |
| 			keys[k].value[current_thread] = NULL;
 | |
| 		}
 | |
| 
 | |
| 		if (value != NULL) {
 | |
| 			/* Note: calling mthread_exit() from a destructor
 | |
| 			 * causes undefined behavior.
 | |
| 			 */
 | |
| 			keys[k].destr(value);
 | |
| 
 | |
| 			found = TRUE;
 | |
| 		}
 | |
| 	}
 | |
|   } while (found);
 | |
| }
 |