#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); | |
} |