commit b20b42b837d396112c0bf08e610bc3e074f673b4 from: rsc date: Wed Aug 10 18:48:31 2005 UTC Ridiculous amount of work for OpenBSD. commit - c15ce40c4456d3bb6d44092bb22097ad93768c3a commit + b20b42b837d396112c0bf08e610bc3e074f673b4 blob - 3dbb3b2a8bd1c3abfbf9e8c217baf0adc7731834 blob + fdbc712ad6c8b5f007a79b13c896d9ec134503fc --- src/libthread/BSD.c +++ src/libthread/BSD.c @@ -397,13 +397,6 @@ _threadsetproc(Proc *p) } void -_pthreadinit(void) -{ - __isthreaded = 1; - signal(SIGUSR2, sigusr2handler); -} - -void _threadpexit(void) { _exit(0); blob - e6ce09b2755e0be936f7844b25c01ec5b1ae9de1 blob + 33fd31138bad3d4e07b29e93a24f8e69181860ba --- src/libthread/FreeBSD.c +++ src/libthread/FreeBSD.c @@ -41,3 +41,9 @@ swapcontext(ucontext_t *oucp, ucontext_t *ucp) return 0; } +void +_pthreadinit(void) +{ + __isthreaded = 1; + signal(SIGUSR2, sigusr2handler); +} blob - 0cfa0d39a83d990babd9efa757328acf90e066b0 blob + ea6788453a8b0598534bc72bf96ff3b3c84ac040 --- src/libthread/OpenBSD.c +++ src/libthread/OpenBSD.c @@ -1,9 +1,33 @@ #include "threadimpl.h" - #include "BSD.c" -static spinlock_t mlock = { 0, 0, NULL, 0 }; +#include +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +enum { + FD_READ = 1, + FD_WRITE, + FD_RDWR, + FDTBL_MAXSIZE = 128 +}; + +struct fd_entry { + QLock lock; + int fd; + int id; + short rc; + 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 _thread_malloc_lock(void) { @@ -20,3 +44,139 @@ void _thread_malloc_init(void) { } + +/* + * Must set errno on failure because the return value + * 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 +_thread_dl_lock(int t) +{ + if(t) + _spinunlock(&dl_lock); + else + _spinlock(&dl_lock); +} + +void +_pthreadinit(void) +{ + __isthreaded = 1; + dlctl(nil, DL_SETTHREADLCK, _thread_dl_lock); + signal(SIGUSR2, sigusr2handler); +}