2011-03-30 12:46:40 +00:00
|
|
|
#include "u.h"
|
|
|
|
#include "tos.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
#include "../port/error.h"
|
|
|
|
#include "edf.h"
|
|
|
|
|
|
|
|
#include <a.out.h>
|
|
|
|
|
|
|
|
int shargs(char*, int, char**);
|
|
|
|
|
|
|
|
extern void checkpages(void);
|
|
|
|
extern void checkpagerefs(void);
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
sysr1(va_list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2013-06-09 23:09:52 +00:00
|
|
|
if(!iseve())
|
|
|
|
error(Eperm);
|
2011-03-30 12:46:40 +00:00
|
|
|
checkpagerefs();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-05-28 21:41:54 +00:00
|
|
|
static void
|
|
|
|
abortion(void*)
|
|
|
|
{
|
|
|
|
pexit("fork aborted", 1);
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
sysrfork(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
Proc *p;
|
|
|
|
int n, i;
|
|
|
|
Fgrp *ofg;
|
|
|
|
Pgrp *opg;
|
|
|
|
Rgrp *org;
|
|
|
|
Egrp *oeg;
|
|
|
|
ulong pid, flag;
|
|
|
|
Mach *wm;
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
flag = va_arg(list, ulong);
|
2011-03-30 12:46:40 +00:00
|
|
|
/* Check flags before we commit */
|
|
|
|
if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG))
|
|
|
|
error(Ebadarg);
|
|
|
|
if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG))
|
|
|
|
error(Ebadarg);
|
|
|
|
if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
|
|
|
|
error(Ebadarg);
|
|
|
|
|
|
|
|
if((flag&RFPROC) == 0) {
|
|
|
|
if(flag & (RFMEM|RFNOWAIT))
|
|
|
|
error(Ebadarg);
|
|
|
|
if(flag & (RFFDG|RFCFDG)) {
|
|
|
|
ofg = up->fgrp;
|
|
|
|
if(flag & RFFDG)
|
|
|
|
up->fgrp = dupfgrp(ofg);
|
|
|
|
else
|
|
|
|
up->fgrp = dupfgrp(nil);
|
|
|
|
closefgrp(ofg);
|
|
|
|
}
|
|
|
|
if(flag & (RFNAMEG|RFCNAMEG)) {
|
|
|
|
opg = up->pgrp;
|
|
|
|
up->pgrp = newpgrp();
|
|
|
|
if(flag & RFNAMEG)
|
|
|
|
pgrpcpy(up->pgrp, opg);
|
|
|
|
/* inherit noattach */
|
|
|
|
up->pgrp->noattach = opg->noattach;
|
|
|
|
closepgrp(opg);
|
|
|
|
}
|
|
|
|
if(flag & RFNOMNT)
|
|
|
|
up->pgrp->noattach = 1;
|
|
|
|
if(flag & RFREND) {
|
|
|
|
org = up->rgrp;
|
|
|
|
up->rgrp = newrgrp();
|
|
|
|
closergrp(org);
|
|
|
|
}
|
|
|
|
if(flag & (RFENVG|RFCENVG)) {
|
|
|
|
oeg = up->egrp;
|
|
|
|
up->egrp = smalloc(sizeof(Egrp));
|
|
|
|
up->egrp->ref = 1;
|
|
|
|
if(flag & RFENVG)
|
|
|
|
envcpy(up->egrp, oeg);
|
|
|
|
closeegrp(oeg);
|
|
|
|
}
|
|
|
|
if(flag & RFNOTEG)
|
2011-12-20 21:22:08 +00:00
|
|
|
up->noteid = pidalloc(0);
|
2011-03-30 12:46:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = newproc();
|
|
|
|
|
|
|
|
p->scallnr = up->scallnr;
|
|
|
|
p->s = up->s;
|
|
|
|
p->nerrlab = 0;
|
|
|
|
p->slash = up->slash;
|
|
|
|
p->dot = up->dot;
|
|
|
|
incref(p->dot);
|
|
|
|
|
|
|
|
memmove(p->note, up->note, sizeof(p->note));
|
|
|
|
p->privatemem = up->privatemem;
|
|
|
|
p->noswap = up->noswap;
|
|
|
|
p->nnote = up->nnote;
|
|
|
|
p->notified = 0;
|
|
|
|
p->lastnote = up->lastnote;
|
|
|
|
p->notify = up->notify;
|
|
|
|
p->ureg = up->ureg;
|
|
|
|
p->dbgreg = 0;
|
|
|
|
|
2013-05-28 21:41:54 +00:00
|
|
|
/* Abort the child process on error */
|
|
|
|
if(waserror()){
|
|
|
|
p->kp = 1;
|
|
|
|
kprocchild(p, abortion, 0);
|
|
|
|
ready(p);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
/* Make a new set of memory segments */
|
|
|
|
n = flag & RFMEM;
|
|
|
|
qlock(&p->seglock);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&p->seglock);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
for(i = 0; i < NSEG; i++)
|
2014-06-22 13:12:45 +00:00
|
|
|
if(up->seg[i] != nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
p->seg[i] = dupseg(up->seg, i, n);
|
|
|
|
qunlock(&p->seglock);
|
|
|
|
poperror();
|
|
|
|
|
|
|
|
/* File descriptors */
|
|
|
|
if(flag & (RFFDG|RFCFDG)) {
|
|
|
|
if(flag & RFFDG)
|
|
|
|
p->fgrp = dupfgrp(up->fgrp);
|
|
|
|
else
|
|
|
|
p->fgrp = dupfgrp(nil);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
p->fgrp = up->fgrp;
|
|
|
|
incref(p->fgrp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process groups */
|
|
|
|
if(flag & (RFNAMEG|RFCNAMEG)) {
|
|
|
|
p->pgrp = newpgrp();
|
|
|
|
if(flag & RFNAMEG)
|
|
|
|
pgrpcpy(p->pgrp, up->pgrp);
|
|
|
|
/* inherit noattach */
|
|
|
|
p->pgrp->noattach = up->pgrp->noattach;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
p->pgrp = up->pgrp;
|
|
|
|
incref(p->pgrp);
|
|
|
|
}
|
|
|
|
if(flag & RFNOMNT)
|
2012-08-27 15:50:48 +00:00
|
|
|
p->pgrp->noattach = 1;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
if(flag & RFREND)
|
|
|
|
p->rgrp = newrgrp();
|
|
|
|
else {
|
|
|
|
incref(up->rgrp);
|
|
|
|
p->rgrp = up->rgrp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Environment group */
|
|
|
|
if(flag & (RFENVG|RFCENVG)) {
|
|
|
|
p->egrp = smalloc(sizeof(Egrp));
|
|
|
|
p->egrp->ref = 1;
|
|
|
|
if(flag & RFENVG)
|
|
|
|
envcpy(p->egrp, up->egrp);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
p->egrp = up->egrp;
|
|
|
|
incref(p->egrp);
|
|
|
|
}
|
|
|
|
p->hang = up->hang;
|
|
|
|
p->procmode = up->procmode;
|
2012-11-23 19:27:09 +00:00
|
|
|
if(up->procctl == Proc_tracesyscall)
|
|
|
|
p->procctl = Proc_tracesyscall;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2013-05-28 21:41:54 +00:00
|
|
|
poperror(); /* abortion */
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
/* Craft a return frame which will cause the child to pop out of
|
|
|
|
* the scheduler in user mode with the return register zero
|
|
|
|
*/
|
|
|
|
forkchild(p, up->dbgreg);
|
|
|
|
|
|
|
|
p->parent = up;
|
2012-11-07 19:46:30 +00:00
|
|
|
if((flag&RFNOWAIT) == 0){
|
|
|
|
p->parentpid = up->pid;
|
2011-03-30 12:46:40 +00:00
|
|
|
lock(&up->exl);
|
|
|
|
up->nchild++;
|
|
|
|
unlock(&up->exl);
|
|
|
|
}
|
|
|
|
if((flag&RFNOTEG) == 0)
|
|
|
|
p->noteid = up->noteid;
|
|
|
|
|
|
|
|
pid = p->pid;
|
|
|
|
memset(p->time, 0, sizeof(p->time));
|
|
|
|
p->time[TReal] = MACHP(0)->ticks;
|
|
|
|
|
|
|
|
kstrdup(&p->text, up->text);
|
|
|
|
kstrdup(&p->user, up->user);
|
2011-07-12 13:46:22 +00:00
|
|
|
|
|
|
|
procfork(p);
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
/*
|
|
|
|
* since the bss/data segments are now shareable,
|
|
|
|
* any mmu info about this process is now stale
|
|
|
|
* (i.e. has bad properties) and has to be discarded.
|
|
|
|
*/
|
|
|
|
flushmmu();
|
|
|
|
p->basepri = up->basepri;
|
|
|
|
p->priority = up->basepri;
|
|
|
|
p->fixedpri = up->fixedpri;
|
|
|
|
p->mp = up->mp;
|
|
|
|
wm = up->wired;
|
|
|
|
if(wm)
|
|
|
|
procwired(p, wm->machno);
|
|
|
|
ready(p);
|
|
|
|
sched();
|
2014-01-20 01:16:42 +00:00
|
|
|
return pid;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static ulong
|
|
|
|
l2be(long l)
|
|
|
|
{
|
|
|
|
uchar *cp;
|
|
|
|
|
|
|
|
cp = (uchar*)&l;
|
|
|
|
return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
sysexec(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
Segment *s, *ts;
|
|
|
|
int i;
|
|
|
|
Chan *tc;
|
2014-01-19 23:47:55 +00:00
|
|
|
char **argv, **argp, **argp0;
|
2011-03-30 12:46:40 +00:00
|
|
|
char *a, *charp, *args, *file, *file0;
|
|
|
|
char *progarg[sizeof(Exec)/2+1], *elem, progelem[64];
|
2014-01-19 23:47:55 +00:00
|
|
|
ulong magic, ssize, nargs, nbytes, n;
|
2014-02-01 09:16:55 +00:00
|
|
|
uintptr t, d, b, entry, bssend, text, data, bss, tstk, align;
|
2013-05-26 22:59:43 +00:00
|
|
|
int indir;
|
2011-03-30 12:46:40 +00:00
|
|
|
Exec exec;
|
|
|
|
char line[sizeof(Exec)];
|
|
|
|
Fgrp *f;
|
|
|
|
Image *img;
|
|
|
|
Tos *tos;
|
|
|
|
|
2014-02-02 14:11:19 +00:00
|
|
|
args = elem = nil;
|
2014-01-19 23:47:55 +00:00
|
|
|
file0 = va_arg(list, char*);
|
|
|
|
validaddr((uintptr)file0, 1, 0);
|
|
|
|
argp0 = va_arg(list, char**);
|
2015-08-06 06:47:38 +00:00
|
|
|
evenaddr((uintptr)argp0);
|
|
|
|
validaddr((uintptr)argp0, 2*BY2WD, 0);
|
|
|
|
if(*argp0 == nil)
|
|
|
|
error(Ebadarg);
|
2014-01-19 23:47:55 +00:00
|
|
|
file0 = validnamedup(file0, 1);
|
2011-03-30 12:46:40 +00:00
|
|
|
if(waserror()){
|
|
|
|
free(file0);
|
2013-09-17 23:07:06 +00:00
|
|
|
free(elem);
|
2014-02-02 14:11:19 +00:00
|
|
|
free(args);
|
2012-10-14 17:48:46 +00:00
|
|
|
/* Disaster after commit */
|
2013-05-26 22:59:43 +00:00
|
|
|
if(!up->seg[SSEG])
|
2012-10-14 17:48:46 +00:00
|
|
|
pexit(up->errstr, 1);
|
2011-03-30 12:46:40 +00:00
|
|
|
nexterror();
|
|
|
|
}
|
2014-02-01 09:16:55 +00:00
|
|
|
align = BY2PG;
|
2013-09-17 23:07:06 +00:00
|
|
|
indir = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
file = file0;
|
|
|
|
for(;;){
|
|
|
|
tc = namec(file, Aopen, OEXEC, 0);
|
|
|
|
if(waserror()){
|
|
|
|
cclose(tc);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
if(!indir)
|
|
|
|
kstrdup(&elem, up->genbuf);
|
|
|
|
|
|
|
|
n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0);
|
2015-07-09 06:03:18 +00:00
|
|
|
if(n <= 2)
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Ebadexec);
|
2015-07-09 06:34:20 +00:00
|
|
|
magic = l2be(exec.magic);
|
2015-07-09 06:51:38 +00:00
|
|
|
if(n == sizeof(Exec) && (magic == AOUT_MAGIC)){
|
2015-07-09 06:03:18 +00:00
|
|
|
entry = l2be(exec.entry);
|
2015-07-10 21:56:39 +00:00
|
|
|
text = l2be(exec.text);
|
|
|
|
if(magic & HDR_MAGIC)
|
2014-02-01 09:16:55 +00:00
|
|
|
text += 8;
|
2015-07-10 21:56:39 +00:00
|
|
|
switch(magic){
|
|
|
|
case S_MAGIC: /* 2MB segment alignment for amd64 */
|
|
|
|
align = 0x200000;
|
2015-03-22 16:49:28 +00:00
|
|
|
break;
|
2015-07-10 21:56:39 +00:00
|
|
|
case V_MAGIC: /* 16K segment alignment for mips */
|
|
|
|
align = 0x4000;
|
2015-03-22 16:49:28 +00:00
|
|
|
break;
|
2014-02-01 09:16:55 +00:00
|
|
|
}
|
2013-12-29 05:11:18 +00:00
|
|
|
if(text >= (USTKTOP-USTKSIZE)-(UTZERO+sizeof(Exec))
|
2011-03-30 12:46:40 +00:00
|
|
|
|| entry < UTZERO+sizeof(Exec)
|
|
|
|
|| entry >= UTZERO+sizeof(Exec)+text)
|
|
|
|
error(Ebadexec);
|
|
|
|
break; /* for binary */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process #! /bin/sh args ...
|
|
|
|
*/
|
2015-07-09 06:03:18 +00:00
|
|
|
memmove(line, &exec, n);
|
2011-03-30 12:46:40 +00:00
|
|
|
if(indir || line[0]!='#' || line[1]!='!')
|
|
|
|
error(Ebadexec);
|
|
|
|
n = shargs(line, n, progarg);
|
2015-07-09 06:03:18 +00:00
|
|
|
if(n < 1)
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Ebadexec);
|
|
|
|
indir = 1;
|
|
|
|
/*
|
|
|
|
* First arg becomes complete file name
|
|
|
|
*/
|
|
|
|
progarg[n++] = file;
|
2015-07-09 06:03:18 +00:00
|
|
|
progarg[n] = nil;
|
2014-01-19 23:47:55 +00:00
|
|
|
argp0++;
|
2011-03-30 12:46:40 +00:00
|
|
|
file = progarg[0];
|
|
|
|
if(strlen(elem) >= sizeof progelem)
|
|
|
|
error(Ebadexec);
|
|
|
|
strcpy(progelem, elem);
|
|
|
|
progarg[0] = progelem;
|
|
|
|
poperror();
|
|
|
|
cclose(tc);
|
|
|
|
}
|
|
|
|
|
|
|
|
data = l2be(exec.data);
|
|
|
|
bss = l2be(exec.bss);
|
2014-02-01 09:16:55 +00:00
|
|
|
align--;
|
|
|
|
t = (UTZERO+sizeof(Exec)+text+align) & ~align;
|
|
|
|
align = BY2PG-1;
|
|
|
|
d = (t + data + align) & ~align;
|
2011-03-30 12:46:40 +00:00
|
|
|
bssend = t + data + bss;
|
2014-02-01 09:16:55 +00:00
|
|
|
b = (bssend + align) & ~align;
|
2013-12-29 05:11:18 +00:00
|
|
|
if(t >= (USTKTOP-USTKSIZE) || d >= (USTKTOP-USTKSIZE) || b >= (USTKTOP-USTKSIZE))
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Ebadexec);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Args: pass 1: count
|
|
|
|
*/
|
|
|
|
nbytes = sizeof(Tos); /* hole for profiling clock at top of stack (and more) */
|
|
|
|
nargs = 0;
|
|
|
|
if(indir){
|
|
|
|
argp = progarg;
|
2014-06-22 13:12:45 +00:00
|
|
|
while(*argp != nil){
|
2011-03-30 12:46:40 +00:00
|
|
|
a = *argp++;
|
|
|
|
nbytes += strlen(a) + 1;
|
|
|
|
nargs++;
|
|
|
|
}
|
|
|
|
}
|
2014-01-19 23:47:55 +00:00
|
|
|
argp = argp0;
|
2015-08-06 06:47:38 +00:00
|
|
|
while(*argp != nil){
|
2011-03-30 12:46:40 +00:00
|
|
|
a = *argp++;
|
2014-01-19 23:47:55 +00:00
|
|
|
if(((uintptr)argp&(BY2PG-1)) < BY2WD)
|
|
|
|
validaddr((uintptr)argp, BY2WD, 0);
|
|
|
|
validaddr((uintptr)a, 1, 0);
|
2011-03-30 12:46:40 +00:00
|
|
|
nbytes += ((char*)vmemchr(a, 0, 0x7FFFFFFF) - a) + 1;
|
|
|
|
nargs++;
|
|
|
|
}
|
|
|
|
ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 8-byte align SP for those (e.g. sparc) that need it.
|
|
|
|
* execregs() will subtract another 4 bytes for argc.
|
|
|
|
*/
|
2014-02-05 18:48:36 +00:00
|
|
|
if(BY2WD == 4 && (ssize+4) & 7)
|
2011-03-30 12:46:40 +00:00
|
|
|
ssize += 4;
|
2013-03-16 01:37:07 +00:00
|
|
|
|
|
|
|
if(PGROUND(ssize) >= USTKSIZE)
|
|
|
|
error(Enovmem);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Build the stack segment, putting it in kernel virtual for the moment
|
|
|
|
*/
|
|
|
|
qlock(&up->seglock);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&up->seglock);
|
|
|
|
nexterror();
|
|
|
|
}
|
2013-03-16 01:37:07 +00:00
|
|
|
|
|
|
|
s = up->seg[SSEG];
|
|
|
|
do {
|
|
|
|
tstk = s->base;
|
|
|
|
if(tstk <= USTKSIZE)
|
|
|
|
error(Enovmem);
|
|
|
|
} while((s = isoverlap(up, tstk-USTKSIZE, USTKSIZE)) != nil);
|
|
|
|
up->seg[ESEG] = newseg(SG_STACK, tstk-USTKSIZE, USTKSIZE/BY2PG);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Args: pass 2: assemble; the pages will be faulted in
|
|
|
|
*/
|
2013-03-16 01:37:07 +00:00
|
|
|
tos = (Tos*)(tstk - sizeof(Tos));
|
2011-03-30 12:46:40 +00:00
|
|
|
tos->cyclefreq = m->cyclefreq;
|
2011-10-25 18:17:39 +00:00
|
|
|
tos->kcycles = 0;
|
|
|
|
tos->pcycles = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
tos->clock = 0;
|
2011-10-25 18:17:39 +00:00
|
|
|
|
2013-03-16 01:37:07 +00:00
|
|
|
argv = (char**)(tstk - ssize);
|
|
|
|
charp = (char*)(tstk - nbytes);
|
2014-02-02 14:11:19 +00:00
|
|
|
a = charp;
|
2011-03-30 12:46:40 +00:00
|
|
|
if(indir)
|
|
|
|
argp = progarg;
|
|
|
|
else
|
2014-01-19 23:47:55 +00:00
|
|
|
argp = argp0;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
for(i=0; i<nargs; i++){
|
2014-06-22 13:12:45 +00:00
|
|
|
if(indir && *argp==nil) {
|
2011-03-30 12:46:40 +00:00
|
|
|
indir = 0;
|
2014-01-19 23:47:55 +00:00
|
|
|
argp = argp0;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2013-03-16 01:37:07 +00:00
|
|
|
*argv++ = charp + (USTKTOP-tstk);
|
2011-03-30 12:46:40 +00:00
|
|
|
n = strlen(*argp) + 1;
|
|
|
|
memmove(charp, *argp++, n);
|
|
|
|
charp += n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy args; easiest from new process's stack */
|
2014-02-02 14:11:19 +00:00
|
|
|
n = charp - a;
|
2011-03-30 12:46:40 +00:00
|
|
|
if(n > 128) /* don't waste too much space on huge arg lists */
|
|
|
|
n = 128;
|
2014-02-02 14:11:19 +00:00
|
|
|
args = smalloc(n);
|
|
|
|
memmove(args, a, n);
|
|
|
|
if(n>0 && args[n-1]!='\0'){
|
2011-03-30 12:46:40 +00:00
|
|
|
/* make sure last arg is NUL-terminated */
|
|
|
|
/* put NUL at UTF-8 character boundary */
|
|
|
|
for(i=n-1; i>0; --i)
|
2014-02-02 14:11:19 +00:00
|
|
|
if(fullrune(args+i, n-i))
|
2011-03-30 12:46:40 +00:00
|
|
|
break;
|
2014-02-02 14:11:19 +00:00
|
|
|
args[i] = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
n = i+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Committed.
|
|
|
|
* Free old memory.
|
|
|
|
* Special segments are maintained across exec
|
|
|
|
*/
|
|
|
|
for(i = SSEG; i <= BSEG; i++) {
|
|
|
|
putseg(up->seg[i]);
|
|
|
|
/* prevent a second free if we have an error */
|
2014-06-22 13:12:45 +00:00
|
|
|
up->seg[i] = nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2013-05-26 22:59:43 +00:00
|
|
|
for(i = ESEG+1; i < NSEG; i++) {
|
2011-03-30 12:46:40 +00:00
|
|
|
s = up->seg[i];
|
2014-06-22 13:12:45 +00:00
|
|
|
if(s != nil && (s->type&SG_CEXEC) != 0) {
|
2011-03-30 12:46:40 +00:00
|
|
|
putseg(s);
|
2014-06-22 13:12:45 +00:00
|
|
|
up->seg[i] = nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Close on exec
|
|
|
|
*/
|
2014-06-22 13:12:45 +00:00
|
|
|
if((f = up->fgrp) != nil) {
|
2013-05-26 22:59:43 +00:00
|
|
|
for(i=0; i<=f->maxfd; i++)
|
|
|
|
fdclose(i, CCEXEC);
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/* Text. Shared. Attaches to cache image if possible */
|
|
|
|
/* attachimage returns a locked cache image */
|
|
|
|
img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT);
|
|
|
|
ts = img->s;
|
|
|
|
up->seg[TSEG] = ts;
|
|
|
|
ts->flushme = 1;
|
|
|
|
ts->fstart = 0;
|
|
|
|
ts->flen = sizeof(Exec)+text;
|
|
|
|
unlock(img);
|
|
|
|
|
|
|
|
/* Data. Shared. */
|
|
|
|
s = newseg(SG_DATA, t, (d-t)>>PGSHIFT);
|
|
|
|
up->seg[DSEG] = s;
|
|
|
|
|
|
|
|
/* Attached by hand */
|
|
|
|
incref(img);
|
|
|
|
s->image = img;
|
|
|
|
s->fstart = ts->fstart+ts->flen;
|
|
|
|
s->flen = data;
|
|
|
|
|
|
|
|
/* BSS. Zero fill on demand */
|
|
|
|
up->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Move the stack
|
|
|
|
*/
|
|
|
|
s = up->seg[ESEG];
|
2014-06-22 13:12:45 +00:00
|
|
|
up->seg[ESEG] = nil;
|
2012-01-23 04:12:05 +00:00
|
|
|
s->base = USTKTOP-USTKSIZE;
|
|
|
|
s->top = USTKTOP;
|
2013-03-16 01:37:07 +00:00
|
|
|
relocateseg(s, USTKTOP-tstk);
|
2011-03-30 12:46:40 +00:00
|
|
|
up->seg[SSEG] = s;
|
|
|
|
qunlock(&up->seglock);
|
|
|
|
poperror(); /* seglock */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* '/' processes are higher priority (hack to make /ip more responsive).
|
|
|
|
*/
|
|
|
|
if(devtab[tc->type]->dc == L'/')
|
|
|
|
up->basepri = PriRoot;
|
|
|
|
up->priority = up->basepri;
|
2012-10-14 17:48:46 +00:00
|
|
|
poperror(); /* tc */
|
2013-05-26 22:59:43 +00:00
|
|
|
cclose(tc);
|
|
|
|
poperror(); /* file0 */
|
|
|
|
free(file0);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
qlock(&up->debug);
|
2013-09-17 23:07:06 +00:00
|
|
|
free(up->text);
|
|
|
|
up->text = elem;
|
|
|
|
free(up->args);
|
2014-02-02 14:11:19 +00:00
|
|
|
up->args = args;
|
2013-09-17 23:07:06 +00:00
|
|
|
up->nargs = n;
|
|
|
|
up->setargs = 0;
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
up->nnote = 0;
|
|
|
|
up->notify = 0;
|
|
|
|
up->notified = 0;
|
|
|
|
up->privatemem = 0;
|
2014-08-16 22:50:20 +00:00
|
|
|
up->noswap = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
procsetup(up);
|
|
|
|
qunlock(&up->debug);
|
2011-07-12 13:46:22 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* At this point, the mmu contains info about the old address
|
|
|
|
* space and needs to be flushed
|
|
|
|
*/
|
|
|
|
flushmmu();
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
if(up->hang)
|
|
|
|
up->procctl = Proc_stopme;
|
|
|
|
return execregs(entry, ssize, nargs);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
shargs(char *s, int n, char **ap)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
s += 2;
|
|
|
|
n -= 2; /* skip #! */
|
2015-07-09 06:03:18 +00:00
|
|
|
for(i=0;; i++){
|
|
|
|
if(i >= n)
|
2011-03-30 12:46:40 +00:00
|
|
|
return 0;
|
2015-07-09 06:03:18 +00:00
|
|
|
if(s[i]=='\n')
|
|
|
|
break;
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
s[i] = 0;
|
2015-07-09 06:03:18 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
i = 0;
|
|
|
|
for(;;) {
|
|
|
|
while(*s==' ' || *s=='\t')
|
|
|
|
s++;
|
|
|
|
if(*s == 0)
|
|
|
|
break;
|
2015-07-09 06:03:18 +00:00
|
|
|
ap[i++] = s++;
|
2011-03-30 12:46:40 +00:00
|
|
|
while(*s && *s!=' ' && *s!='\t')
|
|
|
|
s++;
|
|
|
|
if(*s == 0)
|
|
|
|
break;
|
2015-07-09 06:03:18 +00:00
|
|
|
*s++ = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2015-07-09 06:03:18 +00:00
|
|
|
ap[i] = nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
return0(void*)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
syssleep(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-01-19 23:47:55 +00:00
|
|
|
long ms;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
ms = va_arg(list, long);
|
|
|
|
if(ms <= 0) {
|
2014-06-22 13:12:45 +00:00
|
|
|
if (up->edf != nil && (up->edf->flags & Admitted))
|
2011-03-30 12:46:40 +00:00
|
|
|
edfyield();
|
|
|
|
else
|
|
|
|
yield();
|
2014-01-19 23:47:55 +00:00
|
|
|
} else {
|
|
|
|
if(ms < TK2MS(1))
|
|
|
|
ms = TK2MS(1);
|
|
|
|
tsleep(&up->sleep, return0, 0, ms);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
sysalarm(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-01-20 01:16:42 +00:00
|
|
|
return procalarm(va_arg(list, ulong));
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
|
|
|
|
uintptr
|
|
|
|
sysexits(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
char *status;
|
|
|
|
char *inval = "invalid exit string";
|
|
|
|
char buf[ERRMAX];
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
status = va_arg(list, char*);
|
2014-06-22 13:12:45 +00:00
|
|
|
if(status != nil){
|
2011-03-30 12:46:40 +00:00
|
|
|
if(waserror())
|
|
|
|
status = inval;
|
|
|
|
else{
|
2014-01-19 23:47:55 +00:00
|
|
|
validaddr((uintptr)status, 1, 0);
|
2011-03-30 12:46:40 +00:00
|
|
|
if(vmemchr(status, 0, ERRMAX) == 0){
|
|
|
|
memmove(buf, status, ERRMAX);
|
|
|
|
buf[ERRMAX-1] = 0;
|
|
|
|
status = buf;
|
|
|
|
}
|
|
|
|
poperror();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
pexit(status, 1);
|
2014-01-19 23:47:55 +00:00
|
|
|
return 0; /* not reached */
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
sys_wait(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-01-20 01:16:42 +00:00
|
|
|
ulong pid;
|
2011-03-30 12:46:40 +00:00
|
|
|
Waitmsg w;
|
|
|
|
OWaitmsg *ow;
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
ow = va_arg(list, OWaitmsg*);
|
2014-01-20 01:16:42 +00:00
|
|
|
if(ow == nil)
|
2014-01-19 23:47:55 +00:00
|
|
|
pid = pwait(nil);
|
|
|
|
else {
|
|
|
|
validaddr((uintptr)ow, sizeof(OWaitmsg), 1);
|
|
|
|
evenaddr((uintptr)ow);
|
|
|
|
pid = pwait(&w);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2014-01-20 01:16:42 +00:00
|
|
|
if(ow != nil){
|
|
|
|
readnum(0, ow->pid, NUMSIZE, w.pid, NUMSIZE);
|
|
|
|
readnum(0, ow->time+TUser*NUMSIZE, NUMSIZE, w.time[TUser], NUMSIZE);
|
|
|
|
readnum(0, ow->time+TSys*NUMSIZE, NUMSIZE, w.time[TSys], NUMSIZE);
|
|
|
|
readnum(0, ow->time+TReal*NUMSIZE, NUMSIZE, w.time[TReal], NUMSIZE);
|
|
|
|
strncpy(ow->msg, w.msg, sizeof(ow->msg)-1);
|
|
|
|
ow->msg[sizeof(ow->msg)-1] = '\0';
|
|
|
|
}
|
|
|
|
return pid;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
sysawait(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-01-19 23:47:55 +00:00
|
|
|
char *p;
|
2011-03-30 12:46:40 +00:00
|
|
|
Waitmsg w;
|
2014-01-19 23:47:55 +00:00
|
|
|
uint n;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
p = va_arg(list, char*);
|
|
|
|
n = va_arg(list, uint);
|
|
|
|
validaddr((uintptr)p, n, 1);
|
2014-01-20 01:16:42 +00:00
|
|
|
pwait(&w);
|
|
|
|
return (uintptr)snprint(p, n, "%d %lud %lud %lud %q",
|
|
|
|
w.pid,
|
|
|
|
w.time[TUser], w.time[TSys], w.time[TReal],
|
|
|
|
w.msg);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
werrstr(char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list va;
|
|
|
|
|
|
|
|
if(up == nil)
|
|
|
|
return;
|
|
|
|
|
|
|
|
va_start(va, fmt);
|
|
|
|
vseprint(up->syserrstr, up->syserrstr+ERRMAX, fmt, va);
|
|
|
|
va_end(va);
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
static int
|
2011-03-30 12:46:40 +00:00
|
|
|
generrstr(char *buf, uint nbuf)
|
|
|
|
{
|
|
|
|
char tmp[ERRMAX];
|
|
|
|
|
|
|
|
if(nbuf == 0)
|
|
|
|
error(Ebadarg);
|
2014-01-19 23:47:55 +00:00
|
|
|
validaddr((uintptr)buf, nbuf, 1);
|
2011-03-30 12:46:40 +00:00
|
|
|
if(nbuf > sizeof tmp)
|
|
|
|
nbuf = sizeof tmp;
|
|
|
|
memmove(tmp, buf, nbuf);
|
|
|
|
|
|
|
|
/* make sure it's NUL-terminated */
|
|
|
|
tmp[nbuf-1] = '\0';
|
|
|
|
memmove(buf, up->syserrstr, nbuf);
|
|
|
|
buf[nbuf-1] = '\0';
|
|
|
|
memmove(up->syserrstr, tmp, nbuf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
syserrstr(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-01-19 23:47:55 +00:00
|
|
|
char *buf;
|
|
|
|
uint len;
|
|
|
|
|
|
|
|
buf = va_arg(list, char*);
|
|
|
|
len = va_arg(list, uint);
|
|
|
|
return (uintptr)generrstr(buf, len);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* compatibility for old binaries */
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
sys_errstr(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-01-19 23:47:55 +00:00
|
|
|
return (uintptr)generrstr(va_arg(list, char*), 64);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
sysnotify(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-01-19 23:47:55 +00:00
|
|
|
int (*f)(void*, char*);
|
|
|
|
f = va_arg(list, void*);
|
2014-06-22 13:12:45 +00:00
|
|
|
if(f != nil)
|
2014-01-19 23:47:55 +00:00
|
|
|
validaddr((uintptr)f, sizeof(void*), 0);
|
|
|
|
up->notify = f;
|
2011-03-30 12:46:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
sysnoted(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-06-22 13:12:45 +00:00
|
|
|
if(va_arg(list, int) != NRSTR && !up->notified)
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Egreg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
syssegbrk(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr addr;
|
2011-03-30 12:46:40 +00:00
|
|
|
Segment *s;
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
addr = va_arg(list, uintptr);
|
2011-03-30 12:46:40 +00:00
|
|
|
for(i = 0; i < NSEG; i++) {
|
|
|
|
s = up->seg[i];
|
2014-06-22 13:12:45 +00:00
|
|
|
if(s == nil || addr < s->base || addr >= s->top)
|
2011-03-30 12:46:40 +00:00
|
|
|
continue;
|
|
|
|
switch(s->type&SG_TYPE) {
|
|
|
|
case SG_TEXT:
|
|
|
|
case SG_DATA:
|
|
|
|
case SG_STACK:
|
2015-03-03 12:08:29 +00:00
|
|
|
case SG_PHYSICAL:
|
2015-04-12 20:30:30 +00:00
|
|
|
case SG_FIXED:
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Ebadarg);
|
|
|
|
default:
|
2014-01-19 23:47:55 +00:00
|
|
|
return (uintptr)ibrk(va_arg(list, uintptr), i);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
error(Ebadarg);
|
2014-01-19 23:47:55 +00:00
|
|
|
return 0; /* not reached */
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
syssegattach(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-01-19 23:47:55 +00:00
|
|
|
ulong attr;
|
|
|
|
char *name;
|
|
|
|
uintptr va;
|
|
|
|
ulong len;
|
|
|
|
|
|
|
|
attr = va_arg(list, ulong);
|
|
|
|
name = va_arg(list, char*);
|
|
|
|
va = va_arg(list, uintptr);
|
|
|
|
len = va_arg(list, ulong);
|
|
|
|
return segattach(up, attr, name, va, len);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
syssegdetach(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr addr;
|
2011-03-30 12:46:40 +00:00
|
|
|
Segment *s;
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
addr = va_arg(list, uintptr);
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
qlock(&up->seglock);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&up->seglock);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
s = nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
for(i = 0; i < NSEG; i++)
|
2014-06-22 13:12:45 +00:00
|
|
|
if((s = up->seg[i]) != nil) {
|
|
|
|
qlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
if((addr >= s->base && addr < s->top) ||
|
|
|
|
(s->top == s->base && addr == s->base))
|
|
|
|
goto found;
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
error(Ebadarg);
|
|
|
|
|
|
|
|
found:
|
|
|
|
/*
|
|
|
|
* Check we are not detaching the initial stack segment.
|
|
|
|
*/
|
|
|
|
if(s == up->seg[SSEG]){
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Ebadarg);
|
|
|
|
}
|
2014-06-22 13:12:45 +00:00
|
|
|
up->seg[i] = nil;
|
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
putseg(s);
|
|
|
|
qunlock(&up->seglock);
|
|
|
|
poperror();
|
|
|
|
|
|
|
|
/* Ensure we flush any entries from the lost segment */
|
|
|
|
flushmmu();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
syssegfree(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
Segment *s;
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr from, to;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
from = va_arg(list, uintptr);
|
2015-03-07 17:59:06 +00:00
|
|
|
to = va_arg(list, ulong);
|
|
|
|
to += from;
|
|
|
|
if(to < from)
|
|
|
|
error(Ebadarg);
|
2011-03-30 12:46:40 +00:00
|
|
|
s = seg(up, from, 1);
|
|
|
|
if(s == nil)
|
|
|
|
error(Ebadarg);
|
2014-01-19 23:47:55 +00:00
|
|
|
to &= ~(BY2PG-1);
|
2011-03-30 12:46:40 +00:00
|
|
|
from = PGROUND(from);
|
2015-03-07 17:59:06 +00:00
|
|
|
if(from >= to) {
|
|
|
|
qunlock(s);
|
|
|
|
return 0;
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
if(to > s->top) {
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Ebadarg);
|
|
|
|
}
|
|
|
|
mfreeseg(s, from, (to - from) / BY2PG);
|
2014-06-22 13:12:45 +00:00
|
|
|
qunlock(s);
|
2011-03-30 12:46:40 +00:00
|
|
|
flushmmu();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* For binary compatibility */
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
sysbrk_(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-01-19 23:47:55 +00:00
|
|
|
return (uintptr)ibrk(va_arg(list, uintptr), BSEG);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
sysrendezvous(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr tag, val, new;
|
2011-03-30 12:46:40 +00:00
|
|
|
Proc *p, **l;
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
tag = va_arg(list, uintptr);
|
|
|
|
new = va_arg(list, uintptr);
|
2011-03-30 12:46:40 +00:00
|
|
|
l = &REND(up->rgrp, tag);
|
|
|
|
|
|
|
|
lock(up->rgrp);
|
2014-06-22 13:12:45 +00:00
|
|
|
for(p = *l; p != nil; p = p->rendhash) {
|
2011-03-30 12:46:40 +00:00
|
|
|
if(p->rendtag == tag) {
|
|
|
|
*l = p->rendhash;
|
|
|
|
val = p->rendval;
|
2014-01-19 23:47:55 +00:00
|
|
|
p->rendval = new;
|
2012-02-05 23:23:38 +00:00
|
|
|
unlock(up->rgrp);
|
2013-05-26 22:59:43 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
ready(p);
|
2013-05-26 22:59:43 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
l = &p->rendhash;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Going to sleep here */
|
|
|
|
up->rendtag = tag;
|
2014-01-19 23:47:55 +00:00
|
|
|
up->rendval = new;
|
2011-03-30 12:46:40 +00:00
|
|
|
up->rendhash = *l;
|
|
|
|
*l = up;
|
|
|
|
up->state = Rendezvous;
|
|
|
|
unlock(up->rgrp);
|
|
|
|
|
|
|
|
sched();
|
|
|
|
|
|
|
|
return up->rendval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The implementation of semaphores is complicated by needing
|
|
|
|
* to avoid rescheduling in syssemrelease, so that it is safe
|
|
|
|
* to call from real-time processes. This means syssemrelease
|
|
|
|
* cannot acquire any qlocks, only spin locks.
|
|
|
|
*
|
|
|
|
* Semacquire and semrelease must both manipulate the semaphore
|
|
|
|
* wait list. Lock-free linked lists only exist in theory, not
|
|
|
|
* in practice, so the wait list is protected by a spin lock.
|
|
|
|
*
|
|
|
|
* The semaphore value *addr is stored in user memory, so it
|
|
|
|
* cannot be read or written while holding spin locks.
|
|
|
|
*
|
|
|
|
* Thus, we can access the list only when holding the lock, and
|
|
|
|
* we can access the semaphore only when not holding the lock.
|
|
|
|
* This makes things interesting. Note that sleep's condition function
|
|
|
|
* is called while holding two locks - r and up->rlock - so it cannot
|
|
|
|
* access the semaphore value either.
|
|
|
|
*
|
|
|
|
* An acquirer announces its intention to try for the semaphore
|
|
|
|
* by putting a Sema structure onto the wait list and then
|
|
|
|
* setting Sema.waiting. After one last check of semaphore,
|
|
|
|
* the acquirer sleeps until Sema.waiting==0. A releaser of n
|
|
|
|
* must wake up n acquirers who have Sema.waiting set. It does
|
|
|
|
* this by clearing Sema.waiting and then calling wakeup.
|
|
|
|
*
|
|
|
|
* There are three interesting races here.
|
|
|
|
|
|
|
|
* The first is that in this particular sleep/wakeup usage, a single
|
|
|
|
* wakeup can rouse a process from two consecutive sleeps!
|
|
|
|
* The ordering is:
|
|
|
|
*
|
|
|
|
* (a) set Sema.waiting = 1
|
|
|
|
* (a) call sleep
|
|
|
|
* (b) set Sema.waiting = 0
|
|
|
|
* (a) check Sema.waiting inside sleep, return w/o sleeping
|
|
|
|
* (a) try for semaphore, fail
|
|
|
|
* (a) set Sema.waiting = 1
|
|
|
|
* (a) call sleep
|
|
|
|
* (b) call wakeup(a)
|
|
|
|
* (a) wake up again
|
|
|
|
*
|
|
|
|
* This is okay - semacquire will just go around the loop
|
|
|
|
* again. It does mean that at the top of the for(;;) loop in
|
|
|
|
* semacquire, phore.waiting might already be set to 1.
|
|
|
|
*
|
|
|
|
* The second is that a releaser might wake an acquirer who is
|
|
|
|
* interrupted before he can acquire the lock. Since
|
|
|
|
* release(n) issues only n wakeup calls -- only n can be used
|
|
|
|
* anyway -- if the interrupted process is not going to use his
|
|
|
|
* wakeup call he must pass it on to another acquirer.
|
|
|
|
*
|
|
|
|
* The third race is similar to the second but more subtle. An
|
|
|
|
* acquirer sets waiting=1 and then does a final canacquire()
|
|
|
|
* before going to sleep. The opposite order would result in
|
|
|
|
* missing wakeups that happen between canacquire and
|
|
|
|
* waiting=1. (In fact, the whole point of Sema.waiting is to
|
|
|
|
* avoid missing wakeups between canacquire() and sleep().) But
|
|
|
|
* there can be spurious wakeups between a successful
|
|
|
|
* canacquire() and the following semdequeue(). This wakeup is
|
|
|
|
* not useful to the acquirer, since he has already acquired
|
|
|
|
* the semaphore. Like in the previous case, though, the
|
|
|
|
* acquirer must pass the wakeup call along.
|
|
|
|
*
|
|
|
|
* This is all rather subtle. The code below has been verified
|
|
|
|
* with the spin model /sys/src/9/port/semaphore.p. The
|
|
|
|
* original code anticipated the second race but not the first
|
|
|
|
* or third, which were caught only with spin. The first race
|
|
|
|
* is mentioned in /sys/doc/sleep.ps, but I'd forgotten about it.
|
|
|
|
* It was lucky that my abstract model of sleep/wakeup still managed
|
|
|
|
* to preserve that behavior.
|
|
|
|
*
|
|
|
|
* I remain slightly concerned about memory coherence
|
|
|
|
* outside of locks. The spin model does not take
|
|
|
|
* queued processor writes into account so we have to
|
|
|
|
* think hard. The only variables accessed outside locks
|
|
|
|
* are the semaphore value itself and the boolean flag
|
|
|
|
* Sema.waiting. The value is only accessed with cmpswap,
|
|
|
|
* whose job description includes doing the right thing as
|
|
|
|
* far as memory coherence across processors. That leaves
|
|
|
|
* Sema.waiting. To handle it, we call coherence() before each
|
|
|
|
* read and after each write. - rsc
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Add semaphore p with addr a to list in seg. */
|
|
|
|
static void
|
|
|
|
semqueue(Segment *s, long *a, Sema *p)
|
|
|
|
{
|
|
|
|
memset(p, 0, sizeof *p);
|
|
|
|
p->addr = a;
|
|
|
|
lock(&s->sema); /* uses s->sema.Rendez.Lock, but no one else is */
|
|
|
|
p->next = &s->sema;
|
|
|
|
p->prev = s->sema.prev;
|
|
|
|
p->next->prev = p;
|
|
|
|
p->prev->next = p;
|
|
|
|
unlock(&s->sema);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove semaphore p from list in seg. */
|
|
|
|
static void
|
|
|
|
semdequeue(Segment *s, Sema *p)
|
|
|
|
{
|
|
|
|
lock(&s->sema);
|
|
|
|
p->next->prev = p->prev;
|
|
|
|
p->prev->next = p->next;
|
|
|
|
unlock(&s->sema);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wake up n waiters with addr a on list in seg. */
|
|
|
|
static void
|
|
|
|
semwakeup(Segment *s, long *a, long n)
|
|
|
|
{
|
|
|
|
Sema *p;
|
|
|
|
|
|
|
|
lock(&s->sema);
|
|
|
|
for(p=s->sema.next; p!=&s->sema && n>0; p=p->next){
|
|
|
|
if(p->addr == a && p->waiting){
|
|
|
|
p->waiting = 0;
|
|
|
|
coherence();
|
|
|
|
wakeup(p);
|
|
|
|
n--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unlock(&s->sema);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add delta to semaphore and wake up waiters as appropriate. */
|
|
|
|
static long
|
|
|
|
semrelease(Segment *s, long *addr, long delta)
|
|
|
|
{
|
|
|
|
long value;
|
|
|
|
|
|
|
|
do
|
|
|
|
value = *addr;
|
|
|
|
while(!cmpswap(addr, value, value+delta));
|
|
|
|
semwakeup(s, addr, delta);
|
|
|
|
return value+delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to acquire semaphore using compare-and-swap */
|
|
|
|
static int
|
|
|
|
canacquire(long *addr)
|
|
|
|
{
|
|
|
|
long value;
|
|
|
|
|
|
|
|
while((value=*addr) > 0)
|
|
|
|
if(cmpswap(addr, value, value-1))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Should we wake up? */
|
|
|
|
static int
|
|
|
|
semawoke(void *p)
|
|
|
|
{
|
|
|
|
coherence();
|
|
|
|
return !((Sema*)p)->waiting;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Acquire semaphore (subtract 1). */
|
|
|
|
static int
|
|
|
|
semacquire(Segment *s, long *addr, int block)
|
|
|
|
{
|
|
|
|
int acquired;
|
|
|
|
Sema phore;
|
|
|
|
|
|
|
|
if(canacquire(addr))
|
|
|
|
return 1;
|
|
|
|
if(!block)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
acquired = 0;
|
|
|
|
semqueue(s, addr, &phore);
|
|
|
|
for(;;){
|
|
|
|
phore.waiting = 1;
|
|
|
|
coherence();
|
|
|
|
if(canacquire(addr)){
|
|
|
|
acquired = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(waserror())
|
|
|
|
break;
|
|
|
|
sleep(&phore, semawoke, &phore);
|
|
|
|
poperror();
|
|
|
|
}
|
|
|
|
semdequeue(s, &phore);
|
|
|
|
coherence(); /* not strictly necessary due to lock in semdequeue */
|
|
|
|
if(!phore.waiting)
|
|
|
|
semwakeup(s, addr, 1);
|
|
|
|
if(!acquired)
|
|
|
|
nexterror();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-07-29 18:26:49 +00:00
|
|
|
/* Acquire semaphore or time-out */
|
|
|
|
static int
|
|
|
|
tsemacquire(Segment *s, long *addr, ulong ms)
|
|
|
|
{
|
|
|
|
int acquired, timedout;
|
|
|
|
ulong t, elms;
|
|
|
|
Sema phore;
|
|
|
|
|
|
|
|
if(canacquire(addr))
|
|
|
|
return 1;
|
|
|
|
if(ms == 0)
|
|
|
|
return 0;
|
|
|
|
acquired = timedout = 0;
|
|
|
|
semqueue(s, addr, &phore);
|
|
|
|
for(;;){
|
|
|
|
phore.waiting = 1;
|
|
|
|
coherence();
|
|
|
|
if(canacquire(addr)){
|
|
|
|
acquired = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(waserror())
|
|
|
|
break;
|
|
|
|
t = m->ticks;
|
|
|
|
tsleep(&phore, semawoke, &phore, ms);
|
|
|
|
elms = TK2MS(m->ticks - t);
|
|
|
|
poperror();
|
|
|
|
if(elms >= ms){
|
|
|
|
timedout = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ms -= elms;
|
|
|
|
}
|
|
|
|
semdequeue(s, &phore);
|
|
|
|
coherence(); /* not strictly necessary due to lock in semdequeue */
|
|
|
|
if(!phore.waiting)
|
|
|
|
semwakeup(s, addr, 1);
|
|
|
|
if(timedout)
|
|
|
|
return 0;
|
|
|
|
if(!acquired)
|
|
|
|
nexterror();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
syssemacquire(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
int block;
|
|
|
|
long *addr;
|
|
|
|
Segment *s;
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
addr = va_arg(list, long*);
|
|
|
|
block = va_arg(list, int);
|
|
|
|
evenaddr((uintptr)addr);
|
|
|
|
s = seg(up, (uintptr)addr, 0);
|
|
|
|
if(s == nil || (s->type&SG_RONLY) != 0 || (uintptr)addr+sizeof(long) > s->top){
|
|
|
|
validaddr((uintptr)addr, sizeof(long), 1);
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Ebadarg);
|
2013-09-23 23:52:20 +00:00
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
if(*addr < 0)
|
|
|
|
error(Ebadarg);
|
2014-01-19 23:47:55 +00:00
|
|
|
return (uintptr)semacquire(s, addr, block);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
systsemacquire(va_list list)
|
2012-07-29 18:26:49 +00:00
|
|
|
{
|
|
|
|
long *addr;
|
|
|
|
ulong ms;
|
|
|
|
Segment *s;
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
addr = va_arg(list, long*);
|
|
|
|
ms = va_arg(list, ulong);
|
|
|
|
evenaddr((uintptr)addr);
|
|
|
|
s = seg(up, (uintptr)addr, 0);
|
|
|
|
if(s == nil || (s->type&SG_RONLY) != 0 || (uintptr)addr+sizeof(long) > s->top){
|
|
|
|
validaddr((uintptr)addr, sizeof(long), 1);
|
2012-07-29 18:26:49 +00:00
|
|
|
error(Ebadarg);
|
2013-09-23 23:52:20 +00:00
|
|
|
}
|
2012-07-29 18:26:49 +00:00
|
|
|
if(*addr < 0)
|
|
|
|
error(Ebadarg);
|
2014-01-19 23:47:55 +00:00
|
|
|
return (uintptr)tsemacquire(s, addr, ms);
|
2012-07-29 18:26:49 +00:00
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
syssemrelease(va_list list)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
long *addr, delta;
|
|
|
|
Segment *s;
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
addr = va_arg(list, long*);
|
|
|
|
delta = va_arg(list, long);
|
|
|
|
evenaddr((uintptr)addr);
|
|
|
|
s = seg(up, (uintptr)addr, 0);
|
|
|
|
if(s == nil || (s->type&SG_RONLY) != 0 || (uintptr)addr+sizeof(long) > s->top){
|
|
|
|
validaddr((uintptr)addr, sizeof(long), 1);
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Ebadarg);
|
2013-09-23 23:52:20 +00:00
|
|
|
}
|
2013-05-26 22:59:43 +00:00
|
|
|
/* delta == 0 is a no-op, not a release */
|
2011-03-30 12:46:40 +00:00
|
|
|
if(delta < 0 || *addr < 0)
|
|
|
|
error(Ebadarg);
|
2014-01-19 23:47:55 +00:00
|
|
|
return (uintptr)semrelease(s, addr, delta);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2014-05-20 03:06:31 +00:00
|
|
|
|
|
|
|
/* For binary compatibility */
|
|
|
|
uintptr
|
|
|
|
sys_nsec(va_list list)
|
|
|
|
{
|
|
|
|
vlong *v;
|
|
|
|
|
2014-09-19 23:07:46 +00:00
|
|
|
/* return in register on 64bit machine */
|
|
|
|
if(sizeof(uintptr) == sizeof(vlong)){
|
|
|
|
USED(list);
|
|
|
|
return (uintptr)todget(nil);
|
|
|
|
}
|
|
|
|
|
2014-05-20 03:06:31 +00:00
|
|
|
v = va_arg(list, vlong*);
|
|
|
|
evenaddr((uintptr)v);
|
|
|
|
validaddr((uintptr)v, sizeof(vlong), 1);
|
|
|
|
*v = todget(nil);
|
|
|
|
return 0;
|
|
|
|
}
|