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:
parent
79f8204766
commit
f9b2e9aba4
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue