kernel: generalize awake

Awake can now interrupt several blocking syscalls (even
during note handling).

Among others, it can interrupt await, pread and pwrite.

It cannot interrupt several others for different reasons:

- awake cannot be interrupted by awake;
- syscalls like remove and create can be used for kernel comunication
  and it would be hard to know if the effect occurred in the
  receiving fs if they were interrupted;
- other syscalls do not need awake since they just provide access
  to kernel infos (eg seek or fd2path)

NOTE: awakes registered before a note cannot occur during the note
handling and will be deferred till the next call to noted.
This commit is contained in:
2017-05-15 00:05:59 +02:00
parent 79f8204766
commit f9b2e9aba4
9 changed files with 132 additions and 115 deletions

View File

@ -27,15 +27,15 @@ handler(void *v, char *s)
int i; int i;
if(strcmp(s, "stop") == 0){ if(strcmp(s, "stop") == 0){
done = 1; 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); noted(NCONT);
} }
@ -60,6 +60,8 @@ main(int argc, char**argv)
sleep(100); sleep(100);
if(waited == 2){ if(waited == 2){
print("PASS\n"); print("PASS\n");
exits(0); exits("PASS");
} }
print("%d notes received\n");
exits("FAIL");
} }

View File

@ -21,8 +21,8 @@ echo -n stop > /proc/$testpid/note
wait $testpid wait $testpid
if ( cat $test_output | grep 'waiting after first.........................................................................................................................................................................................................' > /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 'waiting after second.......................' > /dev/null ) {
if ( cat $test_output | grep 'PASS' > /dev/null ) { if ( cat $test_output | grep 'PASS' > /dev/null ) {
rm $test_output rm $test_output
echo PASS echo PASS

View File

@ -237,6 +237,7 @@ syscall(Syscalls scallnr, Ureg* ureg)
m->syscall++; m->syscall++;
up->insyscall = 1; up->insyscall = 1;
up->cursyscall = (Syscalls)scallnr;
up->pc = ureg->ip; up->pc = ureg->ip;
up->dbgreg = ureg; up->dbgreg = ureg;
if(up->trace && (pt = proctrace) != nil) if(up->trace && (pt = proctrace) != nil)
@ -345,6 +346,7 @@ syscall(Syscalls scallnr, Ureg* ureg)
up->insyscall = 0; up->insyscall = 0;
up->psstate = 0; up->psstate = 0;
up->cursyscall = 0;
if(scallnr == SysNoted) if(scallnr == SysNoted)
noted(ureg, ureg->di); noted(ureg, ureg->di);
@ -352,6 +354,8 @@ syscall(Syscalls scallnr, Ureg* ureg)
splhi(); splhi();
if(scallnr != SysRfork && (up->procctl || up->nnote)) if(scallnr != SysRfork && (up->procctl || up->nnote))
notify(ureg); notify(ureg);
else if(canwakeup(scallnr))
awokeproc(up);
/* if we delayed sched because we held a lock, sched now */ /* if we delayed sched because we held a lock, sched now */
if(up->delaysched){ if(up->delaysched){

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of Jehanne. * This file is part of Jehanne.
* *
* Copyright (C) 2015-2016 Giacomo Tesio <giacomo@tesio.it> * Copyright (C) 2015-2017 Giacomo Tesio <giacomo@tesio.it>
* *
* Jehanne is free software: you can redistribute it and/or modify * Jehanne is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -24,6 +24,7 @@
typedef struct PendingWakeup PendingWakeup; typedef struct PendingWakeup PendingWakeup;
struct PendingWakeup struct PendingWakeup
{ {
short notified;
uint64_t time; uint64_t time;
Proc *p; Proc *p;
PendingWakeup *next; PendingWakeup *next;
@ -39,11 +40,53 @@ static QLock l;
static Rendez awaker; 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 * Actually wakeup a process
*/ */
static void static void
wakeupProc(Proc *p) wakeupProc(Proc *p, unsigned long t)
{ {
Mpl pl; Mpl pl;
Rendez *r; Rendez *r;
@ -78,6 +121,7 @@ wakeupProc(Proc *p)
unlock(&p->rlock); unlock(&p->rlock);
splx(pl); splx(pl);
p->pendingWakeup = t;
if(p->state != Rendezvous) if(p->state != Rendezvous)
return; return;
@ -102,28 +146,50 @@ void
awakekproc(void* v) awakekproc(void* v)
{ {
Proc *p; Proc *p;
PendingWakeup *toAwake, *tail; PendingWakeup *tail, *toAwake, **toAwakeEnd, *toDefer, **toDeferEnd;
uint64_t now; uint64_t now;
for(;;){ for(;;){
now = sys->ticks; now = sys->ticks;
toAwake = nil; toAwake = nil;
toAwakeEnd = &toAwake;
toDefer = nil;
toDeferEnd = &toDefer;
/* search for processes to wakeup */ /* search for processes to wakeup */
qlock(&l); qlock(&l);
tail = alarms; tail = alarms;
while(tail && tail->time <= now){ while(tail && tail->time <= now){
if(tail->p->pendingWakeup > tail->p->lastWakeup && tail->p->state >= Ready) if(tail->p->pendingWakeup > tail->p->lastWakeup
break; && tail->p->state >= Ready){
toAwake = tail; *toDeferEnd = tail;
--toAwake->p->wakeups; toDeferEnd = &tail->next;
toAwake->p->pendingWakeup = toAwake->time; } 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; tail = tail->next;
} }
if(toAwake != nil){ if(toAwake != nil){
toAwake->next = nil; *toAwakeEnd = nil;
toAwake = alarms; if(toDefer != nil){
alarms = tail; *toDeferEnd = tail;
alarms = toDefer;
} else {
alarms = tail;
}
} }
qunlock(&l); qunlock(&l);
@ -136,7 +202,7 @@ awakekproc(void* v)
*/ */
if(canqlock(&p->debug)){ if(canqlock(&p->debug)){
if(!waserror()){ if(!waserror()){
wakeupProc(p); wakeupProc(p, toAwake->time);
poperror(); poperror();
} }
qunlock(&p->debug); qunlock(&p->debug);
@ -225,6 +291,7 @@ wakeupafter(int64_t ms)
if(new == nil) if(new == nil)
return 0; return 0;
new->p = up; new->p = up;
new->notified = up->notified;
new->time = when; new->time = when;
qlock(&l); qlock(&l);

View File

@ -609,6 +609,7 @@ struct Proc
Profbuf* prof; Profbuf* prof;
int insyscall; int insyscall;
Syscalls cursyscall;
int32_t blockingfd; /* fd currenly read/written */ int32_t blockingfd; /* fd currenly read/written */
QLock debug; /* to access debugging elements of User */ QLock debug; /* to access debugging elements of User */

View File

@ -48,6 +48,7 @@ char* chanpath(Chan*);
int canlock(Lock*); int canlock(Lock*);
int canqlock(QLock*); int canqlock(QLock*);
int canrlock(RWlock*); int canrlock(RWlock*);
int canwakeup(Syscalls scall);
Chan* cclone(Chan*); Chan* cclone(Chan*);
void cclose(Chan*); void cclose(Chan*);
void ccloseq(Chan*); void ccloseq(Chan*);

View File

@ -568,6 +568,8 @@ newproc(void)
p = psalloc(); p = psalloc();
p->state = Scheding; p->state = Scheding;
p->insyscall = 0;
p->cursyscall = 0;
p->psstate = "New"; p->psstate = "New";
p->mach = 0; p->mach = 0;
p->qnext = 0; p->qnext = 0;
@ -710,7 +712,9 @@ sleep(Rendez *r, int (*f)(void*), void *arg)
*/ */
r->p = up; 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 * if condition happened or a note is pending
* never mind * never mind
@ -751,11 +755,14 @@ sleep(Rendez *r, int (*f)(void*), void *arg)
if(up->notepending && !up->notedeferred) { if(up->notepending && !up->notedeferred) {
up->notepending = 0; up->notepending = 0;
SleepAwakened:
splx(s); splx(s);
if(up->procctl == Proc_exitme && up->closingfgrp) if(up->procctl == Proc_exitme && up->closingfgrp)
forceclosefgrp(); forceclosefgrp();
error(Eintr); error(Eintr);
} }
if(up->insyscall && awakeOnBlock(up) && canwakeup(up->cursyscall))
goto SleepAwakened;
splx(s); splx(s);
} }

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of Jehanne. * This file is part of Jehanne.
* *
* Copyright (C) 2015-2016 Giacomo Tesio <giacomo@tesio.it> * Copyright (C) 2015-2017 Giacomo Tesio <giacomo@tesio.it>
* *
* Jehanne is free software: you can redistribute it and/or modify * Jehanne is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * 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); result = UINT2PTR(up->rendval);
rendezvousDone: rendezvousDone:
awokeproc(up);
return result; return result;
} }
@ -1061,50 +1060,6 @@ semacquire(ProcSegment* s, int* addr, int block)
return 1; 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 int
syssemacquire(int* addr, int block) syssemacquire(int* addr, int block)
{ {
@ -1124,26 +1079,6 @@ syssemacquire(int* addr, int block)
return semacquire(s, addr, 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 int
syssemrelease(int* addr, int delta) syssemrelease(int* addr, int delta)
{ {

View File

@ -25,7 +25,7 @@
"char*", "char*",
"int" "int"
], ],
"Id": 0, "Id": 1,
"Name": "await", "Name": "await",
"Ret": [ "Ret": [
"int" "int"
@ -35,7 +35,7 @@
"Args": [ "Args": [
"long" "long"
], ],
"Id": 1, "Id": 2,
"Name": "awake", "Name": "awake",
"Ret": [ "Ret": [
"long" "long"
@ -47,7 +47,7 @@
"const char*", "const char*",
"int" "int"
], ],
"Id": 2, "Id": 3,
"Name": "bind", "Name": "bind",
"Ret": [ "Ret": [
"int" "int"
@ -57,7 +57,7 @@
"Args": [ "Args": [
"int" "int"
], ],
"Id": 3, "Id": 4,
"Name": "close", "Name": "close",
"Ret": [ "Ret": [
"long" "long"
@ -69,7 +69,7 @@
"long", "long",
"long" "long"
], ],
"Id": 4, "Id": 5,
"Name": "create", "Name": "create",
"Ret": [ "Ret": [
"long" "long"
@ -80,7 +80,7 @@
"char*", "char*",
"int" "int"
], ],
"Id": 5, "Id": 6,
"Name": "errstr", "Name": "errstr",
"Ret": [ "Ret": [
"int" "int"
@ -91,7 +91,7 @@
"const char*", "const char*",
"const char**" "const char**"
], ],
"Id": 6, "Id": 7,
"Name": "exec", "Name": "exec",
"Ret": [ "Ret": [
"uintptr_t" "uintptr_t"
@ -101,7 +101,7 @@
"Args": [ "Args": [
"const char*" "const char*"
], ],
"Id": 7, "Id": 8,
"Name": "_exits", "Name": "_exits",
"Ret": [ "Ret": [
"int" "int"
@ -112,7 +112,7 @@
"int", "int",
"const char*" "const char*"
], ],
"Id": 8, "Id": 9,
"Name": "fauth", "Name": "fauth",
"Ret": [ "Ret": [
"int" "int"
@ -124,7 +124,7 @@
"const char*", "const char*",
"uint32_t" "uint32_t"
], ],
"Id": 9, "Id": 10,
"Name": "fd2path", "Name": "fd2path",
"Ret": [ "Ret": [
"int32_t" "int32_t"
@ -136,7 +136,7 @@
"uint8_t*", "uint8_t*",
"int" "int"
], ],
"Id": 10, "Id": 11,
"Name": "fstat", "Name": "fstat",
"Ret": [ "Ret": [
"long" "long"
@ -149,7 +149,7 @@
"const char*", "const char*",
"int" "int"
], ],
"Id": 11, "Id": 12,
"Name": "fversion", "Name": "fversion",
"Ret": [ "Ret": [
"int" "int"
@ -161,7 +161,7 @@
"const uint8_t*", "const uint8_t*",
"uint32_t" "uint32_t"
], ],
"Id": 12, "Id": 13,
"Name": "fwstat", "Name": "fwstat",
"Ret": [ "Ret": [
"long" "long"
@ -176,7 +176,7 @@
"const char*", "const char*",
"int" "int"
], ],
"Id": 13, "Id": 14,
"Name": "mount", "Name": "mount",
"Ret": [ "Ret": [
"int" "int"
@ -186,7 +186,7 @@
"Args": [ "Args": [
"int" "int"
], ],
"Id": 14, "Id": 15,
"Name": "noted", "Name": "noted",
"Ret": [ "Ret": [
"int" "int"
@ -196,7 +196,7 @@
"Args": [ "Args": [
"const void*" "const void*"
], ],
"Id": 15, "Id": 16,
"Name": "notify", "Name": "notify",
"Ret": [ "Ret": [
"int" "int"
@ -207,7 +207,7 @@
"const char*", "const char*",
"uint32_t" "uint32_t"
], ],
"Id": 16, "Id": 17,
"Name": "open", "Name": "open",
"Ret": [ "Ret": [
"long" "long"
@ -220,7 +220,7 @@
"long", "long",
"long" "long"
], ],
"Id": 17, "Id": 18,
"Name": "pread", "Name": "pread",
"Ret": [ "Ret": [
"long" "long"
@ -233,7 +233,7 @@
"long", "long",
"long" "long"
], ],
"Id": 18, "Id": 19,
"Name": "pwrite", "Name": "pwrite",
"Ret": [ "Ret": [
"long" "long"
@ -243,7 +243,7 @@
"Args": [ "Args": [
"const char*" "const char*"
], ],
"Id": 19, "Id": 20,
"Name": "remove", "Name": "remove",
"Ret": [ "Ret": [
"long" "long"
@ -254,7 +254,7 @@
"const void*", "const void*",
"void*" "void*"
], ],
"Id": 20, "Id": 21,
"Name": "rendezvous", "Name": "rendezvous",
"Ret": [ "Ret": [
"void*" "void*"
@ -264,7 +264,7 @@
"Args": [ "Args": [
"uint32_t" "uint32_t"
], ],
"Id": 21, "Id": 22,
"Name": "rfork", "Name": "rfork",
"Ret": [ "Ret": [
"int" "int"
@ -276,7 +276,7 @@
"long", "long",
"int" "int"
], ],
"Id": 22, "Id": 23,
"Name": "seek", "Name": "seek",
"Ret": [ "Ret": [
"long" "long"
@ -287,7 +287,7 @@
"int*", "int*",
"int" "int"
], ],
"Id": 23, "Id": 24,
"Name": "semacquire", "Name": "semacquire",
"Ret": [ "Ret": [
"int" "int"
@ -298,7 +298,7 @@
"int*", "int*",
"int" "int"
], ],
"Id": 24, "Id": 25,
"Name": "semrelease", "Name": "semrelease",
"Ret": [ "Ret": [
"int" "int"