diff options
Diffstat (limited to 'src/pkg/runtime/openbsd/thread.c')
-rw-r--r-- | src/pkg/runtime/openbsd/thread.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/src/pkg/runtime/openbsd/thread.c b/src/pkg/runtime/openbsd/thread.c new file mode 100644 index 000000000..7e9ba5d67 --- /dev/null +++ b/src/pkg/runtime/openbsd/thread.c @@ -0,0 +1,156 @@ +// Use of this source file is governed by a BSD-style +// license that can be found in the LICENSE file.` + +#include "runtime.h" +#include "defs.h" +#include "os.h" +#include "stack.h" + +extern SigTab runtime·sigtab[]; + +extern int64 runtime·rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); +extern void runtime·sys_sched_yield(void); + +// Basic spinlocks using CAS. We can improve on these later. +static void +lock(Lock *l) +{ + uint32 v; + int32 ret; + + for(;;) { + if(runtime·cas(&l->key, 0, 1)) + return; + runtime·sys_sched_yield(); + } +} + +static void +unlock(Lock *l) +{ + uint32 v; + int32 ret; + + for (;;) { + v = l->key; + if((v&1) == 0) + runtime·throw("unlock of unlocked lock"); + if(runtime·cas(&l->key, v, 0)) + break; + } +} + +void +runtime·lock(Lock *l) +{ + if(m->locks < 0) + runtime·throw("lock count"); + m->locks++; + lock(l); +} + +void +runtime·unlock(Lock *l) +{ + m->locks--; + if(m->locks < 0) + runtime·throw("lock count"); + unlock(l); +} + +// Event notifications. +void +runtime·noteclear(Note *n) +{ + n->lock.key = 0; + lock(&n->lock); +} + +void +runtime·notesleep(Note *n) +{ + lock(&n->lock); + unlock(&n->lock); +} + +void +runtime·notewakeup(Note *n) +{ + unlock(&n->lock); +} + +// From OpenBSD's sys/param.h +#define RFPROC (1<<4) /* change child (else changes curproc) */ +#define RFMEM (1<<5) /* share `address space' */ +#define RFNOWAIT (1<<6) /* parent need not wait() on child */ +#define RFTHREAD (1<<13) /* create a thread, not a process */ + +void +runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) +{ + int32 flags; + int32 ret; + + flags = RFPROC | RFTHREAD | RFMEM | RFNOWAIT; + + if (0) { + runtime·printf( + "newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n", + stk, m, g, fn, m->id, m->tls[0], &m); + } + + m->tls[0] = m->id; // so 386 asm can find it + + if((ret = runtime·rfork_thread(flags, stk, m, g, fn)) < 0) { + runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret); + runtime·printf("runtime: is kern.rthreads disabled?\n"); + + runtime·throw("runtime.newosproc"); + } +} + +void +runtime·osinit(void) +{ +} + +void +runtime·goenvs(void) +{ + runtime·goenvs_unix(); +} + +// Called to initialize a new m (including the bootstrap m). +void +runtime·minit(void) +{ + // Initialize signal handling + m->gsignal = runtime·malg(32*1024); + runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024); +} + +void +runtime·sigpanic(void) +{ + switch(g->sig) { + case SIGBUS: + if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) + runtime·panicstring("invalid memory address or nil pointer dereference"); + runtime·printf("unexpected fault address %p\n", g->sigcode1); + runtime·throw("fault"); + case SIGSEGV: + if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) + runtime·panicstring("invalid memory address or nil pointer dereference"); + runtime·printf("unexpected fault address %p\n", g->sigcode1); + runtime·throw("fault"); + case SIGFPE: + switch(g->sigcode0) { + case FPE_INTDIV: + runtime·panicstring("integer divide by zero"); + case FPE_INTOVF: + runtime·panicstring("integer overflow"); + } + runtime·panicstring("floating point error"); + } + runtime·panicstring(runtime·sigtab[g->sig].name); +} |