diff --git a/qa/kern/nested_note.c b/qa/kern/nested_note.c index da22d4d..ef72b65 100644 --- a/qa/kern/nested_note.c +++ b/qa/kern/nested_note.c @@ -27,15 +27,15 @@ handler(void *v, char *s) int i; if(strcmp(s, "stop") == 0){ done = 1; - noted(NCONT); + }else{ + print("waiting after %s", s); + for(i = 0; i < 1000*1000; ++i) + if(i % 4999 == 0) + print("."); + print("\n"); + print("wait after %s terminated\n", s); + waited++; } - print("waiting after %s", s); - for(i = 0; i < 1000*1000; ++i) - if(i % 4999 == 0) - print("."); - print("\n"); - print("wait after %s terminated\n", s); - waited++; noted(NCONT); } @@ -60,6 +60,8 @@ main(int argc, char**argv) sleep(100); if(waited == 2){ print("PASS\n"); - exits(0); + exits("PASS"); } + print("%d notes received\n"); + exits("FAIL"); } diff --git a/qa/kern/nested_note.runner b/qa/kern/nested_note.runner index 19c49e5..84d2342 100755 --- a/qa/kern/nested_note.runner +++ b/qa/kern/nested_note.runner @@ -21,8 +21,8 @@ echo -n stop > /proc/$testpid/note wait $testpid -if ( cat $test_output | grep 'waiting after first.........................................................................................................................................................................................................' > /dev/null ) { -if ( cat $test_output | grep 'waiting after second.........................................................................................................................................................................................................' > /dev/null ) { +if ( cat $test_output | grep 'waiting after first.......................' > /dev/null ) { +if ( cat $test_output | grep 'waiting after second.......................' > /dev/null ) { if ( cat $test_output | grep 'PASS' > /dev/null ) { rm $test_output echo PASS diff --git a/sys/src/kern/amd64/syscall.c b/sys/src/kern/amd64/syscall.c index 4164798..a1625d6 100644 --- a/sys/src/kern/amd64/syscall.c +++ b/sys/src/kern/amd64/syscall.c @@ -237,6 +237,7 @@ syscall(Syscalls scallnr, Ureg* ureg) m->syscall++; up->insyscall = 1; + up->cursyscall = (Syscalls)scallnr; up->pc = ureg->ip; up->dbgreg = ureg; if(up->trace && (pt = proctrace) != nil) @@ -345,6 +346,7 @@ syscall(Syscalls scallnr, Ureg* ureg) up->insyscall = 0; up->psstate = 0; + up->cursyscall = 0; if(scallnr == SysNoted) noted(ureg, ureg->di); @@ -352,6 +354,8 @@ syscall(Syscalls scallnr, Ureg* ureg) splhi(); if(scallnr != SysRfork && (up->procctl || up->nnote)) notify(ureg); + else if(canwakeup(scallnr)) + awokeproc(up); /* if we delayed sched because we held a lock, sched now */ if(up->delaysched){ diff --git a/sys/src/kern/port/awake.c b/sys/src/kern/port/awake.c index 86c5b27..54d64e6 100644 --- a/sys/src/kern/port/awake.c +++ b/sys/src/kern/port/awake.c @@ -1,7 +1,7 @@ /* * This file is part of Jehanne. * - * Copyright (C) 2015-2016 Giacomo Tesio + * Copyright (C) 2015-2017 Giacomo Tesio * * Jehanne is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +24,7 @@ typedef struct PendingWakeup PendingWakeup; struct PendingWakeup { + short notified; uint64_t time; Proc *p; PendingWakeup *next; @@ -39,11 +40,53 @@ static QLock l; static Rendez awaker; +int +canwakeup(Syscalls scall) +{ + if(scall == 0){ + /* fault set insyscall to 1 */ + return 0; + } + switch(scall){ + default: + panic("canwakeup: unknown scall %d\n", scall); + case SysFstat: + case SysFwstat: + case SysOpen: + case SysPread: + case SysPwrite: + case SysRendezvous: + case SysSemacquire: + case SysSemrelease: + case SysAwait: + return 1; + case SysAwake: + case SysBind: + case SysClose: + case SysCreate: + case SysErrstr: + case SysExec: + case Sys_exits: + case SysFauth: + case SysFd2path: + case SysFversion: + case SysMount: + case SysNoted: + case SysNotify: + case SysRemove: + case SysRfork: + case SysSeek: + case SysUnmount: + case SysAlarm: + return 0; + } +} + /* * Actually wakeup a process */ static void -wakeupProc(Proc *p) +wakeupProc(Proc *p, unsigned long t) { Mpl pl; Rendez *r; @@ -78,6 +121,7 @@ wakeupProc(Proc *p) unlock(&p->rlock); splx(pl); + p->pendingWakeup = t; if(p->state != Rendezvous) return; @@ -102,28 +146,50 @@ void awakekproc(void* v) { Proc *p; - PendingWakeup *toAwake, *tail; + PendingWakeup *tail, *toAwake, **toAwakeEnd, *toDefer, **toDeferEnd; uint64_t now; for(;;){ now = sys->ticks; toAwake = nil; + toAwakeEnd = &toAwake; + toDefer = nil; + toDeferEnd = &toDefer; /* search for processes to wakeup */ qlock(&l); tail = alarms; while(tail && tail->time <= now){ - if(tail->p->pendingWakeup > tail->p->lastWakeup && tail->p->state >= Ready) - break; - toAwake = tail; - --toAwake->p->wakeups; - toAwake->p->pendingWakeup = toAwake->time; + if(tail->p->pendingWakeup > tail->p->lastWakeup + && tail->p->state >= Ready){ + *toDeferEnd = tail; + toDeferEnd = &tail->next; + } else if (!tail->notified && tail->p->notified){ + /* If an awake was requested outside of + * a note handler, it cannot expire + * while executing a note handler. + * On the other hand if an awake was + * requeted while executing a note handler, + * it's up to the note handler to + * forgive it if it's not needed anymore. + */ + *toDeferEnd = tail; + toDeferEnd = &tail->next; + } else { + *toAwakeEnd = tail; + toAwakeEnd = &tail->next; + --tail->p->wakeups; + } tail = tail->next; } if(toAwake != nil){ - toAwake->next = nil; - toAwake = alarms; - alarms = tail; + *toAwakeEnd = nil; + if(toDefer != nil){ + *toDeferEnd = tail; + alarms = toDefer; + } else { + alarms = tail; + } } qunlock(&l); @@ -136,7 +202,7 @@ awakekproc(void* v) */ if(canqlock(&p->debug)){ if(!waserror()){ - wakeupProc(p); + wakeupProc(p, toAwake->time); poperror(); } qunlock(&p->debug); @@ -225,6 +291,7 @@ wakeupafter(int64_t ms) if(new == nil) return 0; new->p = up; + new->notified = up->notified; new->time = when; qlock(&l); diff --git a/sys/src/kern/port/portdat.h b/sys/src/kern/port/portdat.h index d754110..b065a29 100644 --- a/sys/src/kern/port/portdat.h +++ b/sys/src/kern/port/portdat.h @@ -609,6 +609,7 @@ struct Proc Profbuf* prof; int insyscall; + Syscalls cursyscall; int32_t blockingfd; /* fd currenly read/written */ QLock debug; /* to access debugging elements of User */ diff --git a/sys/src/kern/port/portfns.h b/sys/src/kern/port/portfns.h index 260b29b..4aef05d 100644 --- a/sys/src/kern/port/portfns.h +++ b/sys/src/kern/port/portfns.h @@ -48,6 +48,7 @@ char* chanpath(Chan*); int canlock(Lock*); int canqlock(QLock*); int canrlock(RWlock*); +int canwakeup(Syscalls scall); Chan* cclone(Chan*); void cclose(Chan*); void ccloseq(Chan*); diff --git a/sys/src/kern/port/proc.c b/sys/src/kern/port/proc.c index f3317c4..794fbd4 100644 --- a/sys/src/kern/port/proc.c +++ b/sys/src/kern/port/proc.c @@ -568,6 +568,8 @@ newproc(void) p = psalloc(); p->state = Scheding; + p->insyscall = 0; + p->cursyscall = 0; p->psstate = "New"; p->mach = 0; p->qnext = 0; @@ -710,7 +712,9 @@ sleep(Rendez *r, int (*f)(void*), void *arg) */ r->p = up; - if((*f)(arg) || up->notepending && !up->notedeferred){ + if((*f)(arg) + || (up->notepending && !up->notedeferred) + || (up->insyscall && awakeOnBlock(up) && canwakeup(up->cursyscall))){ /* * if condition happened or a note is pending * never mind @@ -751,11 +755,14 @@ sleep(Rendez *r, int (*f)(void*), void *arg) if(up->notepending && !up->notedeferred) { up->notepending = 0; +SleepAwakened: splx(s); if(up->procctl == Proc_exitme && up->closingfgrp) forceclosefgrp(); error(Eintr); } + if(up->insyscall && awakeOnBlock(up) && canwakeup(up->cursyscall)) + goto SleepAwakened; splx(s); } diff --git a/sys/src/kern/port/sysproc.c b/sys/src/kern/port/sysproc.c index cdbbd1f..46e9ffc 100644 --- a/sys/src/kern/port/sysproc.c +++ b/sys/src/kern/port/sysproc.c @@ -1,7 +1,7 @@ /* * This file is part of Jehanne. * - * Copyright (C) 2015-2016 Giacomo Tesio + * Copyright (C) 2015-2017 Giacomo Tesio * * Jehanne is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -858,7 +858,6 @@ sysrendezvous(void* tagp, void* rendvalp) result = UINT2PTR(up->rendval); rendezvousDone: - awokeproc(up); return result; } @@ -1061,50 +1060,6 @@ semacquire(ProcSegment* s, int* addr, int block) return 1; } -/* Acquire semaphore or time-out */ -static int -tsemacquire(ProcSegment* s, int* addr, uint64_t ms) -{ - int acquired, timedout; - uint64_t 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 = sys->ticks; - tsleep(&phore.rend, semawoke, &phore, ms); - elms = TK2MS(sys->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; -} - int syssemacquire(int* addr, int block) { @@ -1124,26 +1079,6 @@ syssemacquire(int* addr, int block) return semacquire(s, addr, block); } -int -systsemacquire(int* addr, uint64_t ms) -{ - ProcSegment *s; - - addr = validaddr(addr, sizeof(int), 1); - - evenaddr(PTR2UINT(addr)); - - s = proc_segment(up, PTR2UINT(addr)); - if(s == nil || (s->permissions&SgWrite) == 0 || (uintptr_t)addr+sizeof(int) > s->top){ - validaddr(addr, sizeof(int), 1); - error(Ebadarg); - } - if(*addr < 0) - error(Ebadarg); - - return tsemacquire(s, addr, ms); -} - int syssemrelease(int* addr, int delta) { diff --git a/sys/src/sysconf.json b/sys/src/sysconf.json index 1e62ab0..37a89ac 100644 --- a/sys/src/sysconf.json +++ b/sys/src/sysconf.json @@ -25,7 +25,7 @@ "char*", "int" ], - "Id": 0, + "Id": 1, "Name": "await", "Ret": [ "int" @@ -35,7 +35,7 @@ "Args": [ "long" ], - "Id": 1, + "Id": 2, "Name": "awake", "Ret": [ "long" @@ -47,7 +47,7 @@ "const char*", "int" ], - "Id": 2, + "Id": 3, "Name": "bind", "Ret": [ "int" @@ -57,7 +57,7 @@ "Args": [ "int" ], - "Id": 3, + "Id": 4, "Name": "close", "Ret": [ "long" @@ -69,7 +69,7 @@ "long", "long" ], - "Id": 4, + "Id": 5, "Name": "create", "Ret": [ "long" @@ -80,7 +80,7 @@ "char*", "int" ], - "Id": 5, + "Id": 6, "Name": "errstr", "Ret": [ "int" @@ -91,7 +91,7 @@ "const char*", "const char**" ], - "Id": 6, + "Id": 7, "Name": "exec", "Ret": [ "uintptr_t" @@ -101,7 +101,7 @@ "Args": [ "const char*" ], - "Id": 7, + "Id": 8, "Name": "_exits", "Ret": [ "int" @@ -112,7 +112,7 @@ "int", "const char*" ], - "Id": 8, + "Id": 9, "Name": "fauth", "Ret": [ "int" @@ -124,7 +124,7 @@ "const char*", "uint32_t" ], - "Id": 9, + "Id": 10, "Name": "fd2path", "Ret": [ "int32_t" @@ -136,7 +136,7 @@ "uint8_t*", "int" ], - "Id": 10, + "Id": 11, "Name": "fstat", "Ret": [ "long" @@ -149,7 +149,7 @@ "const char*", "int" ], - "Id": 11, + "Id": 12, "Name": "fversion", "Ret": [ "int" @@ -161,7 +161,7 @@ "const uint8_t*", "uint32_t" ], - "Id": 12, + "Id": 13, "Name": "fwstat", "Ret": [ "long" @@ -176,7 +176,7 @@ "const char*", "int" ], - "Id": 13, + "Id": 14, "Name": "mount", "Ret": [ "int" @@ -186,7 +186,7 @@ "Args": [ "int" ], - "Id": 14, + "Id": 15, "Name": "noted", "Ret": [ "int" @@ -196,7 +196,7 @@ "Args": [ "const void*" ], - "Id": 15, + "Id": 16, "Name": "notify", "Ret": [ "int" @@ -207,7 +207,7 @@ "const char*", "uint32_t" ], - "Id": 16, + "Id": 17, "Name": "open", "Ret": [ "long" @@ -220,7 +220,7 @@ "long", "long" ], - "Id": 17, + "Id": 18, "Name": "pread", "Ret": [ "long" @@ -233,7 +233,7 @@ "long", "long" ], - "Id": 18, + "Id": 19, "Name": "pwrite", "Ret": [ "long" @@ -243,7 +243,7 @@ "Args": [ "const char*" ], - "Id": 19, + "Id": 20, "Name": "remove", "Ret": [ "long" @@ -254,7 +254,7 @@ "const void*", "void*" ], - "Id": 20, + "Id": 21, "Name": "rendezvous", "Ret": [ "void*" @@ -264,7 +264,7 @@ "Args": [ "uint32_t" ], - "Id": 21, + "Id": 22, "Name": "rfork", "Ret": [ "int" @@ -276,7 +276,7 @@ "long", "int" ], - "Id": 22, + "Id": 23, "Name": "seek", "Ret": [ "long" @@ -287,7 +287,7 @@ "int*", "int" ], - "Id": 23, + "Id": 24, "Name": "semacquire", "Ret": [ "int" @@ -298,7 +298,7 @@ "int*", "int" ], - "Id": 24, + "Id": 25, "Name": "semrelease", "Ret": [ "int"