/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include "compat.h"#include "error.h" #include "errstr.h" ulong kerndate;Proc **privup;char *eve;extern void *mainmem; void_assert(char *fmt){ panic("assert failed: %s", fmt);} interrdepth(int ed){ if(ed >= 0 && up->nerrlab != ed) panic("unbalanced error depth: expected %d got %d\n", ed, up->nerrlab); return up->nerrlab;} voidnewup(char *name){ up = smalloc(sizeof(Proc)); up->user = eve; strncpy(up->name, name, KNAMELEN-1); up->name[KNAMELEN-1] = '\0';} voidkproc(char *name, void (*f)(void *), void *a){ int pid; pid = rfork(RFPROC|RFMEM|RFNOWAIT); switch(pid){ case -1: panic("can't make new thread: %r"); case 0: break; default: return; } newup(name); if(!waserror()) (*f)(a); _exits(nil);} voidkexit(void){ _exits(nil);} voidinitcompat(void){ rfork(RFREND); privup = privalloc(); kerndate = seconds(); eve = getuser(); newup("main");} intopenmode(ulong o){ o &= ~(OTRUNC|OCEXEC|ORCLOSE); if(o > OEXEC) error(Ebadarg); if(o == OEXEC) return OREAD; return o;} voidpanic(char *fmt, ...){ char buf[512]; char buf2[512]; va_list va; va_start(va, fmt); vseprint(buf, buf+sizeof(buf), fmt, va); va_end(va); sprint(buf2, "panic: %s\n", buf); write(2, buf2, strlen(buf2)); exits("error");} void*smalloc(ulong n){ void *p; p = mallocz(n, 1); if(p == nil) panic("out of memory"); setmalloctag(p, getcallerpc(&n)); return p;} longseconds(void){ return time(nil);} voiderror(char *err){ strncpy(up->error, err, ERRMAX); nexterror();} voidnexterror(void){ longjmp(up->errlab[--up->nerrlab], 1);} intreadstr(ulong off, char *buf, ulong n, char *str){ int size; size = strlen(str); if(off >= size) return 0; if(off+n > size) n = size-off; memmove(buf, str+off, n); return n;} void_rendsleep(void* tag){ void *value; for(;;){ value = rendezvous(tag, (void*)0x22a891b8); if(value == (void*)0x7f7713f9) break; if(tag != (void*)~0) panic("_rendsleep: rendezvous mismatch"); }} void_rendwakeup(void* tag){ void *value; for(;;){ value = rendezvous(tag, (void*)0x7f7713f9); if(value == (void*)0x22a891b8) break; if(tag != (void*)~0) panic("_rendwakeup: rendezvous mismatch"); }} voidrendsleep(Rendez *r, int (*f)(void*), void *arg){ lock(&up->rlock); up->r = r; unlock(&up->rlock); lock(r); /* * if condition happened, never mind */ if(up->intr || f(arg)){ unlock(r); goto Done; } /* * now we are committed to * change state and call scheduler */ if(r->p) panic("double sleep"); r->p = up; unlock(r); _rendsleep(r); Done: lock(&up->rlock); up->r = 0; if(up->intr){ up->intr = 0; unlock(&up->rlock); error(Eintr); } unlock(&up->rlock);} intrendwakeup(Rendez *r){ Proc *p; int rv; lock(r); p = r->p; rv = 0; if(p){ r->p = nil; _rendwakeup(r); rv = 1; } unlock(r); return rv;} voidrendintr(void *v){ Proc *p; p = v; lock(&p->rlock); p->intr = 1; if(p->r) rendwakeup(p->r); unlock(&p->rlock);} voidrendclearintr(void){ lock(&up->rlock); up->intr = 0; unlock(&up->rlock);}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include "compat.h"
#include "error.h"
#include "errstr.h"
ulong kerndate;
Proc **privup;
char *eve;
extern void *mainmem;
void
_assert(char *fmt)
{
panic("assert failed: %s", fmt);
}
int
errdepth(int ed)
{
if(ed >= 0 && up->nerrlab != ed)
panic("unbalanced error depth: expected %d got %d\n", ed, up->nerrlab);
return up->nerrlab;
}
void
newup(char *name)
{
up = smalloc(sizeof(Proc));
up->user = eve;
strncpy(up->name, name, KNAMELEN-1);
up->name[KNAMELEN-1] = '\0';
}
void
kproc(char *name, void (*f)(void *), void *a)
{
int pid;
pid = rfork(RFPROC|RFMEM|RFNOWAIT);
switch(pid){
case -1:
panic("can't make new thread: %r");
case 0:
break;
default:
return;
}
newup(name);
if(!waserror())
(*f)(a);
_exits(nil);
}
void
kexit(void)
{
_exits(nil);
}
void
initcompat(void)
{
rfork(RFREND);
privup = privalloc();
kerndate = seconds();
eve = getuser();
newup("main");
}
int
openmode(ulong o)
{
o &= ~(OTRUNC|OCEXEC|ORCLOSE);
if(o > OEXEC)
error(Ebadarg);
if(o == OEXEC)
return OREAD;
return o;
}
void
panic(char *fmt, ...)
{
char buf[512];
char buf2[512];
va_list va;
va_start(va, fmt);
vseprint(buf, buf+sizeof(buf), fmt, va);
va_end(va);
sprint(buf2, "panic: %s\n", buf);
write(2, buf2, strlen(buf2));
exits("error");
}
void*
smalloc(ulong n)
{
void *p;
p = mallocz(n, 1);
if(p == nil)
panic("out of memory");
setmalloctag(p, getcallerpc(&n));
return p;
}
long
seconds(void)
{
return time(nil);
}
void
error(char *err)
{
strncpy(up->error, err, ERRMAX);
nexterror();
}
void
nexterror(void)
{
longjmp(up->errlab[--up->nerrlab], 1);
}
int
readstr(ulong off, char *buf, ulong n, char *str)
{
int size;
size = strlen(str);
if(off >= size)
return 0;
if(off+n > size)
n = size-off;
memmove(buf, str+off, n);
return n;
}
void
_rendsleep(void* tag)
{
void *value;
for(;;){
value = rendezvous(tag, (void*)0x22a891b8);
if(value == (void*)0x7f7713f9)
break;
if(tag != (void*)~0)
panic("_rendsleep: rendezvous mismatch");
}
}
void
_rendwakeup(void* tag)
{
void *value;
for(;;){
value = rendezvous(tag, (void*)0x7f7713f9);
if(value == (void*)0x22a891b8)
break;
if(tag != (void*)~0)
panic("_rendwakeup: rendezvous mismatch");
}
}
void
rendsleep(Rendez *r, int (*f)(void*), void *arg)
{
lock(&up->rlock);
up->r = r;
unlock(&up->rlock);
lock(r);
/*
* if condition happened, never mind
*/
if(up->intr || f(arg)){
unlock(r);
goto Done;
}
/*
* now we are committed to
* change state and call scheduler
*/
if(r->p)
panic("double sleep");
r->p = up;
unlock(r);
_rendsleep(r);
Done:
lock(&up->rlock);
up->r = 0;
if(up->intr){
up->intr = 0;
unlock(&up->rlock);
error(Eintr);
}
unlock(&up->rlock);
}
int
rendwakeup(Rendez *r)
{
Proc *p;
int rv;
lock(r);
p = r->p;
rv = 0;
if(p){
r->p = nil;
_rendwakeup(r);
rv = 1;
}
unlock(r);
return rv;
}
void
rendintr(void *v)
{
Proc *p;
p = v;
lock(&p->rlock);
p->intr = 1;
if(p->r)
rendwakeup(p->r);
unlock(&p->rlock);
}
void
rendclearintr(void)
{
lock(&up->rlock);
up->intr = 0;
unlock(&up->rlock);
}