1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <unistd.h>
4
+ #include <limits.h>
5
+
6
+ /* Free timers is a stack of available timer offsets */
7
+ unsigned int freeTimersHead = 0 ;
8
+ unsigned int freeTimers [1000000 ];
9
+
10
+ /* Every timer is a bunch of components */
11
+ unsigned int componentMultiplierMs [5 ] = {10 , 50 , 100 , 500 , 1000 };
12
+
13
+ struct Timer {
14
+ /* Offsets in timers array */
15
+ unsigned int next , prev ;
16
+
17
+ /* The components remaining for this untriggered run */
18
+ unsigned int components [5 ];
19
+
20
+ /* We need to track the original Ms in case of repeat timers */
21
+ unsigned int nextOriginalMs ;
22
+
23
+ /* Overshoot Ms is used to track accumulated overshoot and to remove smallest 10ms when overshot more than 10ms */
24
+ unsigned int overshootMs ;
25
+
26
+ /* What list the timer is in */
27
+ unsigned int componentOffset ;
28
+ };
29
+
30
+ /* Timers are strides over an integer array */
31
+ struct Timer timers [1000000 ];
32
+
33
+ /* Timer to registered callback */
34
+ void (* timerCallbacks [1000000 ])();
35
+
36
+ /* Per component timer doubly linked list (head) */
37
+ unsigned int timerListHead [5 ] = {UINT_MAX , UINT_MAX , UINT_MAX , UINT_MAX , UINT_MAX };
38
+
39
+ void cb () {
40
+ printf ("A timer triggered!\n" );
41
+ }
42
+
43
+ void init () {
44
+ freeTimersHead = 0 ;
45
+ for (int i = 0 ; i < 1000000 ; i ++ ) {
46
+ freeTimers [i ] = i ;
47
+ }
48
+ for (int i = 0 ; i < 5 ; i ++ ) {
49
+ timerListHead [i ] = UINT_MAX ;
50
+ }
51
+ }
52
+
53
+ unsigned int allocateTimer () {
54
+ freeTimersHead ++ ;
55
+ //printf("Allocating timer: %d\n", freeTimers[freeTimersHead - 1]);
56
+ return freeTimers [freeTimersHead - 1 ];
57
+ }
58
+
59
+ void freeTimer (unsigned int timer ) {
60
+ //printf("Freeing timer: %d\n", timer);
61
+ freeTimersHead -- ;
62
+ freeTimers [freeTimersHead ] = timer ;
63
+ }
64
+
65
+ unsigned int divideComponents (unsigned int components [5 ], unsigned int * biggestSetComponent , unsigned int ms ) {
66
+ /* Start on fifth component */
67
+ int biggestComponent = 4 ;
68
+
69
+ while (ms > 0 && biggestComponent >= 0 ) {
70
+ /* Can we divide by this component? */
71
+ if (ms >= componentMultiplierMs [biggestComponent ]) {
72
+ components [biggestComponent ] = ms / componentMultiplierMs [biggestComponent ];
73
+ ms -= components [biggestComponent ] * componentMultiplierMs [biggestComponent ];
74
+
75
+ if (* biggestSetComponent < biggestComponent ) {
76
+ * biggestSetComponent = biggestComponent ;
77
+ }
78
+ }
79
+ biggestComponent -- ;
80
+ }
81
+
82
+ unsigned int overshoot = 0 ;
83
+ if (ms ) {
84
+ components [0 ]++ ;
85
+ overshoot = 10 - ms ;
86
+ }
87
+
88
+ /* Return the overshoot */
89
+ return overshoot ;
90
+ }
91
+
92
+ void addTimerToList (unsigned int timer , unsigned int componentOffset ) {
93
+ unsigned int head = timerListHead [componentOffset ];
94
+ timers [timer ].next = head ;
95
+ timers [timer ].prev = UINT_MAX ;
96
+ if (head != UINT_MAX ) {
97
+ timers [head ].prev = timer ;
98
+ }
99
+ timerListHead [componentOffset ] = timer ;
100
+
101
+ /* Track what list the timer is in */
102
+ timers [timer ].componentOffset = componentOffset ;
103
+ }
104
+
105
+ /* Returns the next timer in the list or UINT_MAX */
106
+ unsigned int removeTimerFromList (unsigned int timer , unsigned int componentOffset ) {
107
+ unsigned int prev = timers [timer ].prev ;
108
+ unsigned int next = timers [timer ].next ;
109
+
110
+ if (prev != UINT_MAX ) {
111
+ timers [prev ].next = next ;
112
+ } else {
113
+ timerListHead [componentOffset ] = next ;
114
+ }
115
+
116
+ if (next != UINT_MAX ) {
117
+ timers [next ].prev = prev ;
118
+ }
119
+
120
+ return next ;
121
+ }
122
+
123
+ unsigned int moveTimerToList (unsigned int timer , unsigned int newComponentOffset ) {
124
+ unsigned int currentComponentOffset = timers [timer ].componentOffset ;
125
+ unsigned int nextTimer = removeTimerFromList (timer , currentComponentOffset );
126
+ addTimerToList (timer , newComponentOffset );
127
+ return nextTimer ;
128
+ }
129
+
130
+ /* Trigger a tick of the given component offset, to be called from system timers */
131
+ void tick (unsigned int componentOffset ) {
132
+ //printf("Tick for %d\n", componentOffset);
133
+
134
+ /* Iterate this list, decrementing the timer components */
135
+ unsigned int timerIterator = timerListHead [componentOffset ];
136
+
137
+ while (timerIterator != UINT_MAX ) {
138
+ //printf("Iterating timer %d\n", timerIterator);
139
+
140
+ /* This timer needs to move to a higher precision list, or trigger */
141
+ if (!-- timers [timerIterator ].components [componentOffset ]) {
142
+
143
+ /* Seek to next non-null component or the 0th component */
144
+ unsigned int nextComponentOffsetForTimer = componentOffset ;
145
+ while (nextComponentOffsetForTimer && timers [timerIterator ].components [nextComponentOffsetForTimer ] == 0 ) {
146
+ nextComponentOffsetForTimer -- ;
147
+ }
148
+
149
+ /* Here we either have a new list to join or we trigger the timer here and now */
150
+ if (timers [timerIterator ].components [nextComponentOffsetForTimer ]) {
151
+ /* This should return the next timerIterator */
152
+ timerIterator = moveTimerToList (timerIterator , nextComponentOffsetForTimer );
153
+ } else {
154
+ /* This callback must not modify the list (but we can handle that later!) */
155
+ timerCallbacks [timerIterator ]();
156
+
157
+ /* If the timer itself is removed in the above callback, below removal will fail */
158
+
159
+ /* And remove the timer (this should return the next timerIterator) */
160
+ timerIterator = removeTimerFromList (timerIterator , componentOffset );
161
+ }
162
+ } else {
163
+ timerIterator = timers [timerIterator ].next ;
164
+ }
165
+ }
166
+ }
167
+
168
+ unsigned int setTimeout_ (void (* cb )(), unsigned int ms ) {
169
+ /* Allocate free timer */
170
+ unsigned int timer = allocateTimer ();
171
+
172
+ /* Divide given ms in components */
173
+ unsigned int biggestSetComponent = 0 ;
174
+ timers [timer ].overshootMs = divideComponents (timers [timer ].components , & biggestSetComponent , ms );
175
+
176
+ //printf("Overshoot by %u ms\n", timers[timer].overshootMs);
177
+ //printf("Biggest set component is %u\n", biggestSetComponent);
178
+
179
+ /* Add the timer to the list of the highest component */
180
+ addTimerToList (timer , biggestSetComponent );
181
+
182
+ /* Set the callback */
183
+ timerCallbacks [timer ] = cb ;
184
+
185
+ return timer ;
186
+ }
187
+
188
+ void clearTimeout_ (unsigned int timer ) {
189
+ /* Unlink the timer from its list */
190
+ removeTimerFromList (timer , timers [timer ].componentOffset );
191
+
192
+ /* Put the timer into free timer circle buffer */
193
+ freeTimer (timer );
194
+ }
0 commit comments