Bad remote file systems can change mtime unexpectedly, and then there is the problem that git rebase and similar operations like to change the files and then change them back, modifying the mtimes but not the content. Avoid spurious Put errors on both of those by checking file content. (False positive "modified since last read" make the real ones difficult to notice.)
125 lines
1.9 KiB
C
125 lines
1.9 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <draw.h>
|
|
#include <thread.h>
|
|
#include <cursor.h>
|
|
#include <mouse.h>
|
|
#include <keyboard.h>
|
|
#include <frame.h>
|
|
#include <fcall.h>
|
|
#include <plumb.h>
|
|
#include <libsec.h>
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
|
|
static Channel* ctimer; /* chan(Timer*)[100] */
|
|
static Timer *timer;
|
|
|
|
static
|
|
uint
|
|
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 *v)
|
|
{
|
|
int i, nt, na, dt, del;
|
|
Timer **t, *x;
|
|
uint old, new;
|
|
|
|
USED(v);
|
|
threadsetname("timerproc");
|
|
rfork(RFFDG);
|
|
t = nil;
|
|
na = 0;
|
|
nt = 0;
|
|
old = msec();
|
|
for(;;){
|
|
sleep(10); /* longer sleeps here delay recv on ctimer, but 10ms should not be noticeable */
|
|
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 = FALSE;
|
|
if(x->cancel){
|
|
timerstop(x);
|
|
del = TRUE;
|
|
}else if(x->dt <= 0){
|
|
/*
|
|
* avoid possible deadlock if client is
|
|
* now sending on ctimer
|
|
*/
|
|
if(nbsendul(x->c, 0) > 0)
|
|
del = TRUE;
|
|
}
|
|
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)
|
|
error("timer realloc failed");
|
|
}
|
|
t[nt++] = x;
|
|
old = msec();
|
|
}
|
|
if(nbrecv(ctimer, &x) > 0)
|
|
goto gotit;
|
|
}
|
|
}
|
|
|
|
void
|
|
timerinit(void)
|
|
{
|
|
ctimer = chancreate(sizeof(Timer*), 100);
|
|
chansetname(ctimer, "ctimer");
|
|
proccreate(timerproc, nil, STACK);
|
|
}
|
|
|
|
Timer*
|
|
timerstart(int dt)
|
|
{
|
|
Timer *t;
|
|
|
|
t = timer;
|
|
if(t)
|
|
timer = timer->next;
|
|
else{
|
|
t = emalloc(sizeof(Timer));
|
|
t->c = chancreate(sizeof(int), 0);
|
|
chansetname(t->c, "tc%p", t->c);
|
|
}
|
|
t->next = nil;
|
|
t->dt = dt;
|
|
t->cancel = FALSE;
|
|
sendp(ctimer, t);
|
|
return t;
|
|
}
|