| #include "threadimpl.h" | 
 | #include "BSD.c" | 
 |  | 
 | #include <dlfcn.h> | 
 |  | 
 | struct thread_tag { | 
 | 	struct thread_tag	*next; | 
 | 	spinlock_t		l; | 
 | 	volatile int		key; | 
 | 	void			*data; | 
 | }; | 
 |  | 
 | static spinlock_t mlock; | 
 | static spinlock_t dl_lock; | 
 | static spinlock_t tag_lock; | 
 | static struct thread_tag *thread_tag_store = nil; | 
 | static uint nextkey = 0; | 
 |  | 
 | void | 
 | _thread_malloc_lock(void) | 
 | { | 
 | 	_spinlock(&mlock); | 
 | } | 
 |  | 
 | void | 
 | _thread_malloc_unlock(void) | 
 | { | 
 | 	_spinunlock(&mlock); | 
 | } | 
 |  | 
 | void | 
 | _thread_malloc_init(void) | 
 | { | 
 | } | 
 |  | 
 | /* | 
 |  * for ld.so | 
 |  */ | 
 | void | 
 | _thread_dl_lock(int t) | 
 | { | 
 | 	if(t) | 
 | 		_spinunlock(&dl_lock); | 
 | 	else | 
 | 		_spinlock(&dl_lock); | 
 | } | 
 |  | 
 | /* | 
 |  * for libc | 
 |  */ | 
 | static void | 
 | _thread_tag_init(void **tag) | 
 | { | 
 | 	struct thread_tag *t; | 
 |  | 
 | 	_spinlock(&tag_lock); | 
 | 	if(*tag == nil) { | 
 | 		t = malloc(sizeof (*t)); | 
 | 		if(t != nil) { | 
 | 			memset(&t->l, 0, sizeof(t->l)); | 
 | 			t->key = nextkey++; | 
 | 			*tag = t; | 
 | 		} | 
 | 	} | 
 | 	_spinunlock(&tag_lock); | 
 | } | 
 |  | 
 | void | 
 | _thread_tag_lock(void **tag) | 
 | { | 
 | 	struct thread_tag *t; | 
 |  | 
 | 	if(*tag == nil) | 
 | 		_thread_tag_init(tag); | 
 | 	t = *tag; | 
 | 	_spinlock(&t->l); | 
 | } | 
 |  | 
 | void | 
 | _thread_tag_unlock(void **tag) | 
 | { | 
 | 	struct thread_tag *t; | 
 |  | 
 | 	if(*tag == nil) | 
 | 		_thread_tag_init(tag); | 
 | 	t = *tag; | 
 | 	_spinunlock(&t->l); | 
 | } | 
 |  | 
 | static void * | 
 | _thread_tag_insert(struct thread_tag *t, void *v) | 
 | { | 
 | 	t->data = v; | 
 | 	t->next = thread_tag_store; | 
 | 	thread_tag_store = t; | 
 | 	return t; | 
 | } | 
 |  | 
 | static void * | 
 | _thread_tag_lookup(struct thread_tag *tag, int size) | 
 | { | 
 | 	struct thread_tag *t; | 
 | 	void *p; | 
 |  | 
 | 	_spinlock(&tag->l); | 
 | 	for(t = thread_tag_store; t != nil; t = t->next) | 
 | 		if(t->key == tag->key) | 
 | 			break; | 
 | 	if(t == nil) { | 
 | 		p = malloc(size); | 
 | 		if(p == nil) { | 
 | 			_spinunlock(&tag->l); | 
 | 			return nil; | 
 | 		} | 
 | 		_thread_tag_insert(tag, p); | 
 | 	} | 
 | 	_spinunlock(&tag->l); | 
 | 	return tag->data; | 
 | } | 
 |  | 
 | void * | 
 | _thread_tag_storage(void **tag, void *storage, size_t n, void *err) | 
 | { | 
 | 	struct thread_tag *t; | 
 | 	void *r; | 
 |  | 
 | 	if(*tag == nil) | 
 | 		_thread_tag_init(tag); | 
 | 	t = *tag; | 
 |  | 
 | 	r = _thread_tag_lookup(t, n); | 
 | 	if(r == nil) | 
 | 		r = err; | 
 | 	else | 
 | 		memcpy(r, storage, n); | 
 | 	return r; | 
 | } | 
 |  | 
 | void | 
 | _pthreadinit(void) | 
 | { | 
 | 	__isthreaded = 1; | 
 | 	dlctl(nil, DL_SETTHREADLCK, _thread_dl_lock); | 
 | 	signal(SIGUSR2, sigusr2handler); | 
 | } |