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:
Giacomo Tesio 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;
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");
}

View File

@ -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

View File

@ -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){

View File

@ -1,7 +1,7 @@
/*
* 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
* 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);

View File

@ -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 */

View File

@ -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*);

View File

@ -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);
}

View File

@ -1,7 +1,7 @@
/*
* 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
* 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)
{

View File

@ -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"