Annotation of OpenXM_contrib2/asir2000/gc/include/private/specific.h, Revision 1.1
1.1 ! noro 1: /*
! 2: * This is a reimplementation of a subset of the pthread_getspecific/setspecific
! 3: * interface. This appears to outperform the standard linuxthreads one
! 4: * by a significant margin.
! 5: * The major restriction is that each thread may only make a single
! 6: * pthread_setspecific call on a single key. (The current data structure
! 7: * doesn't really require that. The restriction should be easily removable.)
! 8: * We don't currently support the destruction functions, though that
! 9: * could be done.
! 10: * We also currently assume that only one pthread_setspecific call
! 11: * can be executed at a time, though that assumption would be easy to remove
! 12: * by adding a lock.
! 13: */
! 14:
! 15: #include <errno.h>
! 16:
! 17: /* Called during key creation or setspecific. */
! 18: /* For the GC we already hold lock. */
! 19: /* Currently allocated objects leak on thread exit. */
! 20: /* That's hard to fix, but OK if we allocate garbage */
! 21: /* collected memory. */
! 22: #define MALLOC_CLEAR(n) GC_INTERNAL_MALLOC(n, NORMAL)
! 23: #define PREFIXED(name) GC_##name
! 24:
! 25: #define TS_CACHE_SIZE 1024
! 26: #define CACHE_HASH(n) (((((long)n) >> 8) ^ (long)n) & (TS_CACHE_SIZE - 1))
! 27: #define TS_HASH_SIZE 1024
! 28: #define HASH(n) (((((long)n) >> 8) ^ (long)n) & (TS_HASH_SIZE - 1))
! 29:
! 30: typedef struct thread_specific_entry {
! 31: unsigned long qtid; /* quick thread id, only for cache */
! 32: void * value;
! 33: pthread_t thread;
! 34: struct thread_specific_entry *next;
! 35: } tse;
! 36:
! 37:
! 38: /* We represent each thread-specific datum as two tables. The first is */
! 39: /* a cache, index by a "quick thread identifier". The "quick" thread */
! 40: /* identifier is an easy to compute value, which is guaranteed to */
! 41: /* determine the thread, though a thread may correspond to more than */
! 42: /* one value. We typically use the address of a page in the stack. */
! 43: /* The second is a hash table, indexed by pthread_self(). It is used */
! 44: /* only as a backup. */
! 45:
! 46: /* Return the "quick thread id". Default version. Assumes page size, */
! 47: /* or at least thread stack separation, is at least 4K. */
! 48: static __inline__ long quick_thread_id() {
! 49: int dummy;
! 50: return (long)(&dummy) >> 12;
! 51: }
! 52:
! 53: #define INVALID_QTID ((unsigned long)(-1))
! 54:
! 55: typedef struct thread_specific_data {
! 56: tse * volatile cache[TS_CACHE_SIZE];
! 57: /* A faster index to the hash table */
! 58: tse * hash[TS_HASH_SIZE];
! 59: pthread_mutex_t lock;
! 60: } tsd;
! 61:
! 62: typedef tsd * PREFIXED(key_t);
! 63:
! 64: extern int PREFIXED(key_create) (tsd ** key_ptr, void (* destructor)(void *));
! 65:
! 66: extern int PREFIXED(setspecific) (tsd * key, void * value);
! 67:
! 68: extern void PREFIXED(remove_specific) (tsd * key);
! 69:
! 70: /* An internal version of getspecific that assumes a cache miss. */
! 71: void * PREFIXED(slow_getspecific) (tsd * key, unsigned long qtid,
! 72: tse * volatile * cache_entry);
! 73:
! 74: static __inline__ void * PREFIXED(getspecific) (tsd * key) {
! 75: long qtid = quick_thread_id();
! 76: unsigned hash_val = CACHE_HASH(qtid);
! 77: tse * volatile * entry_ptr = key -> cache + hash_val;
! 78: tse * entry = *entry_ptr; /* Must be loaded only once. */
! 79: if (entry -> qtid == qtid) return entry -> value;
! 80: return PREFIXED(slow_getspecific) (key, qtid, entry_ptr);
! 81: }
! 82:
! 83:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>