master time.c
ohmu  ·  2026-09-13
  1#include <u.h>
  2#include <libc.h>
  3#include <draw.h>
  4#include <thread.h>
  5#include <cursor.h>
  6#include <mouse.h>
  7#include <keyboard.h>
  8#include <frame.h>
  9#include <fcall.h>
 10#include <plumb.h>
 11#include <libsec.h>
 12#include "dat.h"
 13#include "fns.h"
 14
 15static Channel*	ctimer;	/* chan(Timer*)[100] */
 16static Timer *timer;
 17
 18static
 19uint
 20msec(void)
 21{
 22	return nsec()/1000000;
 23}
 24
 25void
 26timerstop(Timer *t)
 27{
 28	t->next = timer;
 29	timer = t;
 30}
 31
 32void
 33timercancel(Timer *t)
 34{
 35	t->cancel = TRUE;
 36}
 37
 38static
 39void
 40timerproc(void *v)
 41{
 42	int i, nt, na, dt, del;
 43	Timer **t, *x;
 44	uint old, new;
 45
 46	USED(v);
 47	threadsetname("timerproc");
 48	rfork(RFFDG);
 49	t = nil;
 50	na = 0;
 51	nt = 0;
 52	old = msec();
 53	for(;;){
 54		sleep(10);	/* longer sleeps here delay recv on ctimer, but 10ms should not be noticeable */
 55		new = msec();
 56		dt = new-old;
 57		old = new;
 58		if(dt < 0)	/* timer wrapped; go around, losing a tick */
 59			continue;
 60		for(i=0; i<nt; i++){
 61			x = t[i];
 62			x->dt -= dt;
 63			del = FALSE;
 64			if(x->cancel){
 65				timerstop(x);
 66				del = TRUE;
 67			}else if(x->dt <= 0){
 68				/*
 69				 * avoid possible deadlock if client is
 70				 * now sending on ctimer
 71				 */
 72				if(nbsendul(x->c, 0) > 0)
 73					del = TRUE;
 74			}
 75			if(del){
 76				memmove(&t[i], &t[i+1], (nt-i-1)*sizeof t[0]);
 77				--nt;
 78				--i;
 79			}
 80		}
 81		if(nt == 0){
 82			x = recvp(ctimer);
 83	gotit:
 84			if(nt == na){
 85				na += 10;
 86				t = realloc(t, na*sizeof(Timer*));
 87				if(t == nil)
 88					error("timer realloc failed");
 89			}
 90			t[nt++] = x;
 91			old = msec();
 92		}
 93		if(nbrecv(ctimer, &x) > 0)
 94			goto gotit;
 95	}
 96}
 97
 98void
 99timerinit(void)
100{
101	ctimer = chancreate(sizeof(Timer*), 100);
102	chansetname(ctimer, "ctimer");
103	proccreate(timerproc, nil, STACK);
104}
105
106Timer*
107timerstart(int dt)
108{
109	Timer *t;
110
111	t = timer;
112	if(t)
113		timer = timer->next;
114	else{
115		t = emalloc(sizeof(Timer));
116		t->c = chancreate(sizeof(int), 0);
117		chansetname(t->c, "tc%p", t->c);
118	}
119	t->next = nil;
120	t->dt = dt;
121	t->cancel = FALSE;
122	sendp(ctimer, t);
123	return t;
124}