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"
 | 
						|
 | 
						|
PRIVATE int keys_used = 0;
 | 
						|
PRIVATE struct {
 | 
						|
  int used;
 | 
						|
  int nvalues;
 | 
						|
  void *mvalue;
 | 
						|
  void **value;
 | 
						|
  void (*destr)(void *);
 | 
						|
} keys[MTHREAD_KEYS_MAX];
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				mthread_init_keys			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC 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			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int mthread_key_create(mthread_key_t *key, void (*destructor)(void *))
 | 
						|
{
 | 
						|
/* Allocate a key.
 | 
						|
 */
 | 
						|
  mthread_key_t k;
 | 
						|
 | 
						|
  mthread_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			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC int mthread_key_delete(mthread_key_t key)
 | 
						|
{
 | 
						|
/* Free up a key, as well as any associated storage space.
 | 
						|
 */
 | 
						|
 | 
						|
  mthread_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			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC void *mthread_getspecific(mthread_key_t key)
 | 
						|
{
 | 
						|
/* Get this thread's local value for the given key. The default is NULL.
 | 
						|
 */
 | 
						|
 | 
						|
  mthread_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			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC 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_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			     *
 | 
						|
 *===========================================================================*/
 | 
						|
PUBLIC 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);
 | 
						|
}
 |