more strangeness (Tim Wiess)
This commit is contained in:
parent
e58459c7b3
commit
826babae95
1 changed files with 102 additions and 139 deletions
|
|
@ -3,30 +3,18 @@
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
struct thread_tag {
|
||||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
struct thread_tag *next;
|
||||||
|
spinlock_t l;
|
||||||
enum {
|
volatile int key;
|
||||||
FD_READ = 1,
|
void *data;
|
||||||
FD_WRITE,
|
|
||||||
FD_RDWR,
|
|
||||||
FDTBL_MAXSIZE = 128
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fd_entry {
|
static spinlock_t mlock;
|
||||||
QLock lock;
|
static spinlock_t dl_lock;
|
||||||
int fd;
|
static spinlock_t tag_lock;
|
||||||
int id;
|
static struct thread_tag *thread_tag_store = nil;
|
||||||
short rc;
|
static uint nextkey = 0;
|
||||||
short wc;
|
|
||||||
short ref;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct fd_entry fd_entry1 = { .fd -1 };
|
|
||||||
static struct fd_entry *fd_table = nil;
|
|
||||||
static spinlock_t fd_table_lock = { 0, 0, nil, 0 };
|
|
||||||
static spinlock_t mlock = { 0, 0, nil, 0 };
|
|
||||||
static spinlock_t dl_lock = { 0, 0, nil, 0 };
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_thread_malloc_lock(void)
|
_thread_malloc_lock(void)
|
||||||
|
|
@ -46,124 +34,8 @@ _thread_malloc_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Must set errno on failure because the return value
|
* for ld.so
|
||||||
* of _thread_fd_entry is propagated back to the caller
|
|
||||||
* of the thread-wrapped libc function.
|
|
||||||
*/
|
*/
|
||||||
static struct fd_entry *
|
|
||||||
_thread_fd_lookup(int fd)
|
|
||||||
{
|
|
||||||
struct fd_entry *t;
|
|
||||||
static int cursize;
|
|
||||||
int newsize;
|
|
||||||
|
|
||||||
if(fd >= FDTBL_MAXSIZE) {
|
|
||||||
errno = EBADF;
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There are currently only a few libc functions using
|
|
||||||
* _thread_fd_*, which are rarely called by P9P programs.
|
|
||||||
* So the contention for these locks is very small and so
|
|
||||||
* far have usually been limited to a single fd. So
|
|
||||||
* rather than malloc the fd_table everytime we just use
|
|
||||||
* a single fd_entry until a lock request for another fd
|
|
||||||
* comes in.
|
|
||||||
*/
|
|
||||||
if(fd_table == nil)
|
|
||||||
if(fd_entry1.fd == -1) {
|
|
||||||
fd_entry1.fd = fd;
|
|
||||||
return &fd_entry1;
|
|
||||||
} else if(fd_entry1.fd == fd)
|
|
||||||
return &fd_entry1;
|
|
||||||
else {
|
|
||||||
cursize = MAX(fd_entry1.fd, 16);
|
|
||||||
fd_table = malloc(cursize*sizeof(fd_table[0]));
|
|
||||||
if(fd_table == nil) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
memset(fd_table, 0, cursize*sizeof(fd_table[0]));
|
|
||||||
fd_table[fd_entry1.fd] = fd_entry1;
|
|
||||||
}
|
|
||||||
if(fd > cursize) {
|
|
||||||
newsize = MIN(cursize*2, FDTBL_MAXSIZE);
|
|
||||||
t = realloc(fd_table, newsize*sizeof(fd_table[0]));
|
|
||||||
if(t == nil) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
fd_table = t;
|
|
||||||
cursize = newsize;
|
|
||||||
memset(fd_table, 0, cursize*sizeof(fd_table[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return &fd_table[fd];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mutiple readers just share the lock by incrementing the read count.
|
|
||||||
* Writers must obtain an exclusive lock.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
_thread_fd_lock(int fd, int type, struct timespec *time)
|
|
||||||
{
|
|
||||||
struct fd_entry *fde;
|
|
||||||
int id;
|
|
||||||
|
|
||||||
_spinlock(&fd_table_lock);
|
|
||||||
fde = _thread_fd_lookup(fd);
|
|
||||||
if(fde == nil)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if(type == FD_READ) {
|
|
||||||
if(fde->rc++ >= 1 && fde->wc == 0) {
|
|
||||||
_spinunlock(&fd_table_lock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
fde->wc++;
|
|
||||||
_spinunlock(&fd_table_lock);
|
|
||||||
|
|
||||||
/* handle recursion */
|
|
||||||
id = proc()->osprocid;
|
|
||||||
if(id == fde->id) {
|
|
||||||
fde->ref++;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
qlock(&fde->lock);
|
|
||||||
fde->id = id;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_thread_fd_unlock(int fd, int type)
|
|
||||||
{
|
|
||||||
struct fd_entry *fde;
|
|
||||||
int id;
|
|
||||||
|
|
||||||
fde = _thread_fd_lookup(fd);
|
|
||||||
if(fde == nil) {
|
|
||||||
fprint(2, "_thread_fd_unlock: fd %d not in table!\n", fd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(type == FD_READ && --fde->rc >= 1)
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
fde->wc--;
|
|
||||||
|
|
||||||
id = proc()->osprocid;
|
|
||||||
if(id == fde->id && fde->ref > 0) {
|
|
||||||
fde->ref--;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fde->id = 0;
|
|
||||||
qunlock(&fde->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_thread_dl_lock(int t)
|
_thread_dl_lock(int t)
|
||||||
{
|
{
|
||||||
|
|
@ -173,6 +45,97 @@ _thread_dl_lock(int t)
|
||||||
_spinlock(&dl_lock);
|
_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
|
void
|
||||||
_pthreadinit(void)
|
_pthreadinit(void)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue