all repos — acme @ main

fork of the acme editor from plan9port - keybinds, tweaks, config.h, etc

time.c (raw)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <cursor.h>
#include <mouse.h>
#include <keyboard.h>
#include "libframe/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;
}