2016-11-25 17:18:40 +01:00
|
|
|
/*
|
|
|
|
* This file is part of Jehanne.
|
|
|
|
*
|
2017-05-15 00:05:59 +02:00
|
|
|
* Copyright (C) 2015-2017 Giacomo Tesio <giacomo@tesio.it>
|
2016-11-25 17:18:40 +01:00
|
|
|
*
|
|
|
|
* Jehanne is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, version 2 of the License.
|
|
|
|
*
|
|
|
|
* Jehanne is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
/* Requirements:
|
|
|
|
* - each process can register several wakeups
|
|
|
|
* - wakeups registered outside a note handler will not happen
|
|
|
|
* in a note handler
|
|
|
|
* - wakeups registered by a note handler will be deleted on noted()
|
|
|
|
* - all pending wakeups of a process will be deleted on pexit()
|
|
|
|
* - future wakeups can be deleted
|
|
|
|
* - each wakeup will interrupt a blocking syscall
|
|
|
|
*/
|
|
|
|
struct AwakeAlarm /* 24 byte */
|
2016-11-25 17:18:40 +01:00
|
|
|
{
|
2017-08-11 01:47:15 +02:00
|
|
|
Proc* p;
|
|
|
|
AwakeAlarm* next;
|
|
|
|
unsigned char notified;
|
|
|
|
unsigned char done;
|
|
|
|
unsigned long time : 48;
|
|
|
|
};
|
|
|
|
typedef struct AlarmPool
|
|
|
|
{
|
|
|
|
AwakeAlarm* alarms;
|
|
|
|
AwakeAlarm* end;
|
|
|
|
int size;
|
|
|
|
int first;
|
|
|
|
int nfree;
|
|
|
|
Lock l;
|
|
|
|
} AlarmPool;
|
|
|
|
static AlarmPool awkpool;
|
|
|
|
#define alarm2wkp(a) ~((a)->time << 16 | (a) - awkpool.alarms)
|
|
|
|
#define wkp2alarm(a) (awkpool.alarms + (~(a) & 0xffff))
|
|
|
|
|
|
|
|
static AwakeAlarm *registry;
|
|
|
|
static Lock rl;
|
|
|
|
|
|
|
|
|
|
|
|
typedef enum ElapsedAlarmFate
|
|
|
|
{
|
|
|
|
TryAgain,
|
|
|
|
Forget,
|
|
|
|
FreeAndForget
|
|
|
|
} ElapsedAlarmFate;
|
|
|
|
static AwakeAlarm *elapsed, **eEnd = &elapsed;
|
|
|
|
static Lock el;
|
|
|
|
|
|
|
|
static Rendez producer;
|
|
|
|
static Rendez consumer;
|
|
|
|
|
|
|
|
static unsigned long next_wakeup;
|
|
|
|
|
|
|
|
static const int awakeable_syscalls[] = {
|
|
|
|
[SysAwait] = 1,
|
|
|
|
[SysAwake] = 0,
|
|
|
|
[SysBind] = 0,
|
|
|
|
[SysClose] = 0,
|
|
|
|
[SysCreate] = 0,
|
|
|
|
[SysErrstr] = 0,
|
|
|
|
[SysExec] = 0,
|
|
|
|
[Sys_exits] = 0,
|
|
|
|
[SysFauth] = 0,
|
|
|
|
[SysFd2path] = 0,
|
|
|
|
[SysFstat] = 1,
|
|
|
|
[SysFversion] = 0,
|
|
|
|
[SysFwstat] = 1,
|
|
|
|
[SysMount] = 0,
|
|
|
|
[SysNoted] = 0,
|
|
|
|
[SysNotify] = 0,
|
|
|
|
[SysOpen] = 1,
|
|
|
|
[SysPread] = 1,
|
|
|
|
[SysPwrite] = 1,
|
|
|
|
[SysRemove] = 0,
|
|
|
|
[SysRendezvous] = 1,
|
|
|
|
[SysRfork] = 0,
|
|
|
|
[SysSeek] = 0,
|
|
|
|
[SysSemacquire] = 1,
|
|
|
|
[SysSemrelease] = 0,
|
|
|
|
[SysUnmount] = 0,
|
2017-08-13 21:59:03 +02:00
|
|
|
[SysAlarm] = 0
|
2016-11-25 17:18:40 +01:00
|
|
|
};
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
#define DEBUG
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
#ifdef DEBUG
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
void
|
|
|
|
awake_detect_loop(AwakeAlarm *head)
|
2017-05-15 00:05:59 +02:00
|
|
|
{
|
2017-08-11 01:47:15 +02:00
|
|
|
AwakeAlarm *tail;
|
|
|
|
while(head != nil){
|
|
|
|
if(!head->p)
|
|
|
|
panic("awake: free alarm head: %#p, pc %#p", head, getcallerpc());
|
|
|
|
if(head < awkpool.alarms || head > awkpool.end)
|
|
|
|
panic("awake: not an alarm head: %#p, pc %#p", head, getcallerpc());
|
|
|
|
tail = head->next;
|
|
|
|
while(tail != nil){
|
|
|
|
if(!tail->p)
|
|
|
|
panic("awake: free alarm tail: %#p, pc %#p", tail, getcallerpc());
|
|
|
|
if(tail < awkpool.alarms || tail > awkpool.end)
|
|
|
|
panic("awake: not an alarm tail: %#p, pc %#p", tail, getcallerpc());
|
|
|
|
if(head == tail)
|
|
|
|
panic("awake: loop detected");
|
|
|
|
else
|
|
|
|
tail = tail->next;
|
|
|
|
}
|
|
|
|
head = head->next;
|
2017-05-15 00:05:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
AwakeAlarm*
|
|
|
|
awake_find_first_of(Proc* p, AwakeAlarm* head)
|
2016-11-25 17:18:40 +01:00
|
|
|
{
|
2017-08-11 01:47:15 +02:00
|
|
|
AwakeAlarm* a = head;
|
|
|
|
if(head == nil)
|
|
|
|
return nil;
|
|
|
|
while(a < awkpool.end){
|
|
|
|
if(a->p == p)
|
|
|
|
return a;
|
|
|
|
++a;
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
static int
|
|
|
|
awake_can_interrupt(Syscalls scall)
|
|
|
|
{
|
|
|
|
if(scall == 0)
|
|
|
|
panic("awake_can_interrupts on page fault");
|
2017-08-13 21:59:03 +02:00
|
|
|
if(scall >= nelem(awakeable_syscalls) - 1)
|
2017-08-11 01:47:15 +02:00
|
|
|
panic("awake_can_interrupts: unknown syscall %d", scall);
|
|
|
|
return awakeable_syscalls[scall];
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
#else
|
|
|
|
# define awake_detect_loop(h)
|
|
|
|
# define awake_can_interrupt(scall) (awakeable_syscalls[scall])
|
|
|
|
//# undef assert
|
|
|
|
//# define assert(a)
|
|
|
|
#endif
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
static void
|
|
|
|
pool_init(void)
|
|
|
|
{
|
|
|
|
awkpool.size = sys->nproc * (sys->nmach + 1);
|
|
|
|
if(awkpool.size >= 1<<16)
|
|
|
|
awkpool.size = 1<<16; /* we have 16 bit in the wakeup token for the index */
|
|
|
|
awkpool.alarms = malloc(sizeof(AwakeAlarm) * awkpool.size);
|
|
|
|
awkpool.end = awkpool.alarms + awkpool.size;
|
|
|
|
awkpool.nfree = awkpool.size;
|
|
|
|
awkpool.first = 0;
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
static AwakeAlarm*
|
|
|
|
alarm_new(Proc *p)
|
|
|
|
{
|
|
|
|
AwakeAlarm *a;
|
|
|
|
|
|
|
|
lock(&awkpool.l);
|
|
|
|
while(awkpool.nfree <= 2*p->nwakeups){
|
|
|
|
unlock(&awkpool.l);
|
|
|
|
resrcwait("wait-wkp", nil);
|
|
|
|
lock(&awkpool.l);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
2017-08-11 01:47:15 +02:00
|
|
|
/* here we know that nfree > 0... */
|
|
|
|
if(awkpool.first == awkpool.size){
|
|
|
|
/* but we don't now where the first free is */
|
|
|
|
awkpool.first = -1;
|
|
|
|
while(++awkpool.first < awkpool.size && awkpool.alarms[awkpool.first].p)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
assert(awkpool.first < awkpool.size);
|
|
|
|
|
|
|
|
a = awkpool.alarms + awkpool.first;
|
|
|
|
a->p = p;
|
|
|
|
|
|
|
|
if(adec(&awkpool.nfree) > 0){
|
|
|
|
UpdateFirst:
|
|
|
|
while(++awkpool.first < awkpool.size && awkpool.alarms[awkpool.first].p)
|
|
|
|
;
|
|
|
|
if(awkpool.first == awkpool.size){
|
|
|
|
awkpool.first = -1;
|
|
|
|
goto UpdateFirst;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
2017-08-11 01:47:15 +02:00
|
|
|
} else {
|
|
|
|
awkpool.first = awkpool.size;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
2017-08-11 01:47:15 +02:00
|
|
|
unlock(&awkpool.l);
|
|
|
|
|
|
|
|
ainc(&p->nwakeups);
|
|
|
|
a->done = 0;
|
|
|
|
a->notified = p->notified ? 1 : 0;
|
|
|
|
a->time = 0;
|
|
|
|
a->next = nil;
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
static void
|
|
|
|
alarm_free(AwakeAlarm* a)
|
|
|
|
{
|
|
|
|
Proc *p = a->p;
|
|
|
|
#ifdef DEBUG
|
|
|
|
a->next = (void*)getcallerpc();
|
|
|
|
#endif
|
|
|
|
a->p = nil;
|
|
|
|
ainc(&awkpool.nfree);
|
|
|
|
adec(&p->nwakeups);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-08-11 01:47:15 +02:00
|
|
|
awake_fell_asleep(Proc *p)
|
2016-11-25 17:18:40 +01:00
|
|
|
{
|
2017-08-11 01:47:15 +02:00
|
|
|
Syscalls cs = p->cursyscall;
|
|
|
|
if(cs != 0 && cs != SysAwake){
|
|
|
|
/* awake_register might sleep() on alarm_new and we
|
|
|
|
* don't want this sleep to be interrupted.
|
|
|
|
*/
|
|
|
|
p->wakeups[p->notified].blockingsc = cs;
|
|
|
|
p->wakeups[p->notified].fell_asleep = sys->ticks;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
awake_should_wake_up(Proc *p)
|
|
|
|
{
|
|
|
|
AwakeAlarm *a = p->wakeups[p->notified].elapsed;
|
|
|
|
Syscalls blockingsc = p->wakeups[p->notified].blockingsc;
|
|
|
|
return a != nil
|
|
|
|
&& blockingsc
|
|
|
|
&& awake_can_interrupt(blockingsc)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
awake_awakened(Proc *p)
|
|
|
|
{
|
|
|
|
AwakeAlarm *a;
|
|
|
|
Syscalls blockingsc = p->wakeups[p->notified].blockingsc;
|
|
|
|
if(blockingsc && awake_can_interrupt(blockingsc))
|
|
|
|
if(a = xchgm(&p->wakeups[p->notified].elapsed, nil)){
|
|
|
|
p->wakeups[p->notified].awakened = sys->ticks;
|
|
|
|
p->wakeups[p->notified].last = alarm2wkp(a);
|
|
|
|
p->wakeups[p->notified].blockingsc = 0;
|
|
|
|
}
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
/* called from noted() to remove all pending alarms */
|
|
|
|
void
|
|
|
|
awake_gc_note(Proc *p)
|
|
|
|
{
|
|
|
|
AwakeAlarm *a, **last;
|
|
|
|
|
|
|
|
assert(p->notified != 0);
|
|
|
|
|
|
|
|
lock(&rl);
|
|
|
|
awake_detect_loop(registry);
|
|
|
|
|
|
|
|
/* first pending alarm */
|
|
|
|
a = xchgm(&p->wakeups[1].elapsed, nil);
|
|
|
|
p->wakeups[1].blockingsc = 0;
|
|
|
|
|
|
|
|
/* then clear the registry */
|
|
|
|
last = ®istry;
|
|
|
|
for(a = *last; a != nil && p->wakeups[1].count > 0; a = *last) {
|
|
|
|
if(!a->p)
|
|
|
|
panic("awake_reset: free alarm in registry");
|
|
|
|
if(a->p == p && a->notified){
|
|
|
|
adec(&p->wakeups[a->notified].count);
|
|
|
|
*last = a->next;
|
|
|
|
alarm_free(a);
|
|
|
|
} else {
|
|
|
|
last = &a->next;
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
2017-08-11 01:47:15 +02:00
|
|
|
awake_detect_loop(registry);
|
|
|
|
if(registry)
|
|
|
|
next_wakeup = registry->time;
|
|
|
|
unlock(&rl);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-08-11 01:47:15 +02:00
|
|
|
* called from pexit() and sysexec() to clear all pending
|
2016-11-25 17:18:40 +01:00
|
|
|
*/
|
|
|
|
void
|
2017-08-11 01:47:15 +02:00
|
|
|
awake_gc_proc(Proc *p)
|
|
|
|
{
|
|
|
|
AwakeAlarm *a, **last;
|
|
|
|
|
|
|
|
/* clear all wakeups (process is exiting) */
|
|
|
|
lock(&rl);
|
|
|
|
awake_detect_loop(registry);
|
|
|
|
|
|
|
|
/* first pending alarm */
|
|
|
|
p->wakeups[0].elapsed = nil;
|
|
|
|
p->wakeups[0].blockingsc = 0;
|
|
|
|
p->wakeups[1].elapsed = nil;
|
|
|
|
p->wakeups[1].blockingsc = 0;
|
|
|
|
|
|
|
|
/* then clear the registry */
|
|
|
|
last = ®istry;
|
|
|
|
for(a = *last; a != nil && (p->wakeups[0].count > 0 || p->wakeups[1].count > 0); a = *last) {
|
|
|
|
if(!a->p)
|
|
|
|
panic("awake_reset: free alarm in registry");
|
|
|
|
if(a->p == p){
|
|
|
|
adec(&p->wakeups[a->notified].count);
|
|
|
|
*last = a->next;
|
|
|
|
alarm_free(a);
|
|
|
|
} else {
|
|
|
|
last = &a->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
awake_detect_loop(registry);
|
|
|
|
if(registry)
|
|
|
|
next_wakeup = registry->time;
|
|
|
|
unlock(&rl);
|
|
|
|
|
|
|
|
assert(p->wakeups[0].count == 0);
|
|
|
|
assert(p->wakeups[1].count == 0);
|
|
|
|
|
2017-10-10 00:14:49 +02:00
|
|
|
while(p->nwakeups > 0){
|
|
|
|
while(waserror())
|
|
|
|
;
|
2017-08-11 01:47:15 +02:00
|
|
|
resrcwait(nil, nil);
|
2017-10-11 00:36:52 +02:00
|
|
|
poperror();
|
2017-10-10 00:14:49 +02:00
|
|
|
}
|
2017-08-11 01:47:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static long
|
|
|
|
awake_register(long ms)
|
2016-11-25 17:18:40 +01:00
|
|
|
{
|
2017-08-11 01:47:15 +02:00
|
|
|
AwakeAlarm *a, *new, **last;
|
|
|
|
|
|
|
|
new = alarm_new(up);
|
|
|
|
|
|
|
|
ilock(&rl);
|
|
|
|
last = ®istry;
|
|
|
|
awake_detect_loop(registry);
|
|
|
|
|
|
|
|
new->time = (sys->ticks + ms2tk(ms) + sys->nmach) & 0xffffffffffff;
|
|
|
|
for(a = *last; a != nil && a->time <= new->time; a = *last) {
|
|
|
|
if(!a->p)
|
|
|
|
panic("awake_register: free alarm in registry");
|
|
|
|
if(a->done){
|
|
|
|
adec(&a->p->wakeups[a->notified].count);
|
|
|
|
*last = a->next;
|
|
|
|
alarm_free(a);
|
|
|
|
continue;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
2017-08-11 01:47:15 +02:00
|
|
|
if(a->time == new->time && a->p == up){
|
|
|
|
/* avoid two alarms at the same tick for a process */
|
|
|
|
++new->time;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
2017-08-11 01:47:15 +02:00
|
|
|
last = &a->next;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
2017-08-11 01:47:15 +02:00
|
|
|
*last = new;
|
|
|
|
new->next = a;
|
|
|
|
awake_detect_loop(registry);
|
|
|
|
ainc(&up->wakeups[new->notified].count);
|
|
|
|
assert(registry != nil);
|
|
|
|
next_wakeup = registry->time;
|
|
|
|
iunlock(&rl);
|
|
|
|
|
|
|
|
return alarm2wkp(new);
|
|
|
|
}
|
|
|
|
|
|
|
|
static long
|
|
|
|
awake_remove(long request)
|
|
|
|
{
|
|
|
|
AwakeAlarm *a;
|
|
|
|
|
|
|
|
if(request >= up->wakeups[up->notified].last)
|
|
|
|
return 0; /* already free */
|
|
|
|
|
|
|
|
a = wkp2alarm(request);
|
|
|
|
if(a >= awkpool.end)
|
|
|
|
return 0; /* should we send a note to up? */
|
|
|
|
|
|
|
|
if(a->p != up)
|
|
|
|
return 0; /* should we send a note to up? */
|
|
|
|
|
|
|
|
if(a->time != (~request)>>16)
|
|
|
|
return 0; /* should we send a note to up? */
|
|
|
|
|
|
|
|
lock(&rl); /* sync with awake_timer */
|
|
|
|
if(!CASV(&up->wakeups[up->notified].elapsed, a, nil)){
|
|
|
|
a->done = 1;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
2017-08-11 01:47:15 +02:00
|
|
|
unlock(&rl);
|
|
|
|
|
|
|
|
return request;
|
|
|
|
}
|
|
|
|
|
|
|
|
long
|
|
|
|
sysawake(long request)
|
|
|
|
{
|
|
|
|
if(request == 0)
|
|
|
|
return up->wakeups[up->notified].last;
|
|
|
|
if(request < 0)
|
|
|
|
return awake_remove(request);
|
|
|
|
return awake_register(request);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* called every clock tick
|
|
|
|
*/
|
|
|
|
void
|
2017-08-11 01:47:15 +02:00
|
|
|
awake_tick(unsigned long now)
|
2016-11-25 17:18:40 +01:00
|
|
|
{
|
2017-08-11 01:47:15 +02:00
|
|
|
if(next_wakeup < now && (now&7) == 0)
|
|
|
|
wakeup(&producer);
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
static void
|
|
|
|
try_wire_process(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
/* wire to an online processor to reduce context switches
|
|
|
|
* but try to avoid boot processor as it runs awake_tick
|
|
|
|
*/
|
|
|
|
if(up->mach->machno > 0)
|
|
|
|
procwired(up, up->mach->machno);
|
|
|
|
else if(sys->nmach > 1){
|
|
|
|
i = sys->nmach;
|
|
|
|
while(up->wired != nil && i > 1)
|
|
|
|
if(sys->machptr[--i]->online)
|
|
|
|
procwired(up, i);
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
void
|
|
|
|
awake_timer(void* v)
|
2016-11-25 17:18:40 +01:00
|
|
|
{
|
2017-08-11 01:47:15 +02:00
|
|
|
long now;
|
|
|
|
AwakeAlarm **next, *tmp, *toAwake, **toAwakeEnd;
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
try_wire_process();
|
|
|
|
|
|
|
|
/* initialize wakeups wkppool */
|
|
|
|
pool_init();
|
|
|
|
|
|
|
|
CheckWakeups:
|
|
|
|
next_wakeup = ~0;
|
|
|
|
|
|
|
|
/* we fix time to preserve wakeup order */
|
|
|
|
now = sys->ticks;
|
|
|
|
|
|
|
|
toAwake = nil;
|
|
|
|
toAwakeEnd = &toAwake;
|
|
|
|
|
|
|
|
/* search for processes to wakeup */
|
|
|
|
ilock(&rl);
|
|
|
|
next = ®istry;
|
|
|
|
while((tmp = *next) != nil && tmp->time <= now){
|
|
|
|
if(tmp->p == nil)
|
|
|
|
panic("awake_timer: free alarm in registry");
|
|
|
|
if(tmp->done){
|
|
|
|
*next = tmp->next;
|
|
|
|
adec(&tmp->p->wakeups[tmp->notified].count);
|
|
|
|
alarm_free(tmp);
|
|
|
|
} else {
|
|
|
|
if(!CASV(&tmp->p->wakeups[tmp->notified].elapsed, nil, tmp)){
|
|
|
|
/* each wakeup must have a chance */
|
|
|
|
next = &tmp->next;
|
|
|
|
} else {
|
|
|
|
adec(&tmp->p->wakeups[tmp->notified].count);
|
|
|
|
*toAwakeEnd = tmp;
|
|
|
|
toAwakeEnd = &tmp->next;
|
|
|
|
*next = tmp->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(toAwake != nil)
|
|
|
|
*toAwakeEnd = nil;
|
|
|
|
|
|
|
|
awake_detect_loop(registry);
|
|
|
|
iunlock(&rl);
|
|
|
|
|
|
|
|
if(toAwake != nil){
|
|
|
|
/* pass the elapsed wakeups to awake_ringer preserving order */
|
|
|
|
lock(&el);
|
|
|
|
*eEnd = toAwake;
|
|
|
|
eEnd = toAwakeEnd;
|
|
|
|
unlock(&el);
|
|
|
|
wakeup(&consumer);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
if(registry)
|
|
|
|
next_wakeup = registry->time;
|
|
|
|
|
|
|
|
sleep(&producer, return0, 0);
|
|
|
|
goto CheckWakeups;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
/* Try to wake up a process
|
|
|
|
* Returns:
|
|
|
|
* - 0 if the alarm must be preserved in the elapsed list
|
|
|
|
* - 1 if the alarm must be removed from the elapsed list and freed
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
awake_dispatch(AwakeAlarm *a)
|
2016-11-25 17:18:40 +01:00
|
|
|
{
|
2017-08-11 01:47:15 +02:00
|
|
|
int canfree;
|
|
|
|
Rendez *r;
|
|
|
|
Proc *p;
|
|
|
|
Syscalls bs;
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
p = a->p;
|
|
|
|
if(p == nil)
|
|
|
|
panic("awake_dispatch: free alarm in elapsed list");
|
|
|
|
|
|
|
|
if(p < procalloc.arena || p > procalloc.arena + procalloc.nproc)
|
|
|
|
panic("awake_dispatch: dirty alarm");
|
|
|
|
if(!canlock(&p->rlock))
|
2016-11-25 17:18:40 +01:00
|
|
|
return 0;
|
2017-08-11 01:47:15 +02:00
|
|
|
|
|
|
|
/* sched() locks p->rlock before setting p->mach and p->state
|
|
|
|
*/
|
|
|
|
if(p->mach != nil && p->state <= Running){
|
|
|
|
canfree = p->state < Ready;
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(p->wakeups[a->notified].elapsed != a){
|
|
|
|
/* cleared by awake_awakened */
|
|
|
|
canfree = 1;
|
|
|
|
goto Done;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
canfree = 0;
|
|
|
|
|
|
|
|
if(a->done){
|
|
|
|
/* already signaled, we have to wait for awake_awakened */
|
|
|
|
goto Done;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
2017-08-11 01:47:15 +02:00
|
|
|
|
|
|
|
if(a->notified && !p->notified){
|
|
|
|
/* this should never happen because p is not Running:
|
|
|
|
* either noted as been called previously (and thus awake_reset)
|
|
|
|
* or it has not
|
|
|
|
*
|
|
|
|
* so if this happens it's probably a but in awake_reset
|
|
|
|
*/
|
|
|
|
unlock(&p->rlock);
|
|
|
|
panic("awake_dispatch: notified alarm for not notified process");
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
2017-08-11 01:47:15 +02:00
|
|
|
|
|
|
|
if(p->notepending && !p->notedeferred){
|
|
|
|
/* notes take precedence */
|
|
|
|
goto Done;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
bs = p->wakeups[a->notified].blockingsc;
|
|
|
|
if(bs == 0 || !awake_can_interrupt(bs)){
|
|
|
|
/* wait for a chance */
|
|
|
|
goto Done;
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
r = p->r;
|
|
|
|
if(r != nil){
|
|
|
|
if(canlock(&r->l)){
|
|
|
|
if(p->state != Wakeme || r->p != p)
|
|
|
|
panic("awake_dispatch: state %d %d %d", r->p != p, p->r != r, p->state);
|
|
|
|
a->done = 1;
|
|
|
|
p->r = nil;
|
|
|
|
r->p = nil;
|
|
|
|
ready(p);
|
|
|
|
unlock(&r->l);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(p->state == Rendezvous || p->state == Queueing)
|
|
|
|
if(proc_interrupt_finalize(p))
|
|
|
|
a->done = 1;
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
Done:
|
|
|
|
unlock(&p->rlock);
|
|
|
|
return canfree;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
void
|
|
|
|
awake_ringer(void* v)
|
2016-11-25 17:18:40 +01:00
|
|
|
{
|
2017-08-11 01:47:15 +02:00
|
|
|
AwakeAlarm *pending, **pLast, **next, *a;
|
|
|
|
|
|
|
|
pending = nil;
|
|
|
|
pLast = &pending;
|
|
|
|
|
|
|
|
CheckElapsed:
|
|
|
|
lock(&el);
|
|
|
|
*pLast = elapsed;
|
|
|
|
elapsed = nil;
|
|
|
|
eEnd = &elapsed;
|
|
|
|
unlock(&el);
|
|
|
|
|
|
|
|
pLast = &pending;
|
|
|
|
next = pLast;
|
|
|
|
while(*next != nil){
|
|
|
|
a = *next;
|
|
|
|
if(awake_dispatch(a)){
|
|
|
|
*next = a->next;
|
|
|
|
alarm_free(a);
|
|
|
|
} else {
|
|
|
|
*pLast = a;
|
|
|
|
next = &a->next;
|
|
|
|
pLast = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pending == nil){
|
|
|
|
assert(pLast == &pending);
|
|
|
|
sleep(&consumer, return0, 0);
|
|
|
|
} else if(elapsed == nil){
|
|
|
|
tsleep(&up->sleep, return0, 0, 30);
|
|
|
|
}
|
|
|
|
goto CheckElapsed;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|