jehanne/sys/src/cmd/rio/time.c

140 lines
2.6 KiB
C

/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
/* Portions of this file are Copyright (C) 2015-2018 Giacomo Tesio <giacomo@tesio.it>
* See /doc/license/gpl-2.0.txt for details about the licensing.
*/
/* Portions of this file are Copyright (C) 9front's team.
* See /doc/license/9front-mit for details about the licensing.
* See http://git.9front.org/plan9front/plan9front/HEAD/info.html for a list of authors.
*/
#include <u.h>
#include <lib9.h>
#include <draw.h>
#include <thread.h>
#include <cursor.h>
#include <mouse.h>
#include <keyboard.h>
#include <frame.h>
#include <9P2000.h>
#include "dat.h"
#include "fns.h"
static Channel* ctimer; /* chan(Timer*)[100] */
static Timer *timer;
static
uint32_t
msec(void)
{
return nsec()/1000000;
}
void
timerstop(Timer *t)
{
t->next = timer;
timer = t;
}
void
timercancel(Timer *t)
{
t->cancel = TRUE;
}
static
void
timerproc(void* _)
{
int i, nt, na, dt, del;
Timer **t, *x;
uint32_t old, new;
sys_rfork(RFFDG);
threadsetname("TIMERPROC");
t = nil;
na = 0;
nt = 0;
old = msec();
for(;;){
sleep(1); /* will sleep minimum incr */
new = msec();
dt = new-old;
old = new;
if(dt < 0) /* timer wrapped; go around, losing a tick */
continue;
for(i=0; i<nt; i++){
x = t[i];
x->dt -= dt;
del = 0;
if(x->cancel){
timerstop(x);
del = 1;
}else if(x->dt <= 0){
/*
* avoid possible deadlock if client is
* now sending on ctimer
*/
if(nbsendul(x->c, 0) > 0)
del = 1;
}
if(del){
memmove(&t[i], &t[i+1], (nt-i-1)*sizeof t[0]);
--nt;
--i;
}
}
if(nt == 0){
x = recvp(ctimer);
gotit:
if(nt == na){
na += 10;
t = realloc(t, na*sizeof(Timer*));
if(t == nil)
abort();
}
t[nt++] = x;
old = msec();
}
if(nbrecv(ctimer, &x) > 0)
goto gotit;
}
}
void
timerinit(void)
{
ctimer = chancreate(sizeof(Timer*), 100);
proccreate(timerproc, nil, STACK);
}
/*
* timeralloc() and timerfree() don't lock, so can only be
* called from the main proc.
*/
Timer*
timerstart(int dt)
{
Timer *t;
t = timer;
if(t)
timer = timer->next;
else{
t = emalloc(sizeof(Timer));
t->c = chancreate(sizeof(int), 0);
}
t->next = nil;
t->dt = dt;
t->cancel = FALSE;
sendp(ctimer, t);
return t;
}