mirror of
https://github.com/uNetworking/uWebSockets.js.git
synced 2026-04-19 23:00:27 -04:00
194 lines
6.1 KiB
C
194 lines
6.1 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
|
|
/* Free timers is a stack of available timer offsets */
|
|
unsigned int freeTimersHead = 0;
|
|
unsigned int freeTimers[1000000];
|
|
|
|
/* Every timer is a bunch of components */
|
|
unsigned int componentMultiplierMs[5] = {10, 50, 100, 500, 1000};
|
|
|
|
struct Timer {
|
|
/* Offsets in timers array */
|
|
unsigned int next, prev;
|
|
|
|
/* The components remaining for this untriggered run */
|
|
unsigned int components[5];
|
|
|
|
/* We need to track the original Ms in case of repeat timers */
|
|
unsigned int nextOriginalMs;
|
|
|
|
/* Overshoot Ms is used to track accumulated overshoot and to remove smallest 10ms when overshot more than 10ms */
|
|
unsigned int overshootMs;
|
|
|
|
/* What list the timer is in */
|
|
unsigned int componentOffset;
|
|
};
|
|
|
|
/* Timers are strides over an integer array */
|
|
struct Timer timers[1000000];
|
|
|
|
/* Timer to registered callback */
|
|
void (*timerCallbacks[1000000])();
|
|
|
|
/* Per component timer doubly linked list (head) */
|
|
unsigned int timerListHead[5] = {UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX};
|
|
|
|
void cb() {
|
|
printf("A timer triggered!\n");
|
|
}
|
|
|
|
void init() {
|
|
freeTimersHead = 0;
|
|
for (int i = 0; i < 1000000; i++) {
|
|
freeTimers[i] = i;
|
|
}
|
|
for (int i = 0; i < 5; i++) {
|
|
timerListHead[i] = UINT_MAX;
|
|
}
|
|
}
|
|
|
|
unsigned int allocateTimer() {
|
|
freeTimersHead++;
|
|
//printf("Allocating timer: %d\n", freeTimers[freeTimersHead - 1]);
|
|
return freeTimers[freeTimersHead - 1];
|
|
}
|
|
|
|
void freeTimer(unsigned int timer) {
|
|
//printf("Freeing timer: %d\n", timer);
|
|
freeTimersHead--;
|
|
freeTimers[freeTimersHead] = timer;
|
|
}
|
|
|
|
unsigned int divideComponents(unsigned int components[5], unsigned int *biggestSetComponent, unsigned int ms) {
|
|
/* Start on fifth component */
|
|
int biggestComponent = 4;
|
|
|
|
while (ms > 0 && biggestComponent >= 0) {
|
|
/* Can we divide by this component? */
|
|
if (ms >= componentMultiplierMs[biggestComponent]) {
|
|
components[biggestComponent] = ms / componentMultiplierMs[biggestComponent];
|
|
ms -= components[biggestComponent] * componentMultiplierMs[biggestComponent];
|
|
|
|
if (*biggestSetComponent < biggestComponent) {
|
|
*biggestSetComponent = biggestComponent;
|
|
}
|
|
}
|
|
biggestComponent--;
|
|
}
|
|
|
|
unsigned int overshoot = 0;
|
|
if (ms) {
|
|
components[0]++;
|
|
overshoot = 10 - ms;
|
|
}
|
|
|
|
/* Return the overshoot */
|
|
return overshoot;
|
|
}
|
|
|
|
void addTimerToList(unsigned int timer, unsigned int componentOffset) {
|
|
unsigned int head = timerListHead[componentOffset];
|
|
timers[timer].next = head;
|
|
timers[timer].prev = UINT_MAX;
|
|
if (head != UINT_MAX) {
|
|
timers[head].prev = timer;
|
|
}
|
|
timerListHead[componentOffset] = timer;
|
|
|
|
/* Track what list the timer is in */
|
|
timers[timer].componentOffset = componentOffset;
|
|
}
|
|
|
|
/* Returns the next timer in the list or UINT_MAX */
|
|
unsigned int removeTimerFromList(unsigned int timer, unsigned int componentOffset) {
|
|
unsigned int prev = timers[timer].prev;
|
|
unsigned int next = timers[timer].next;
|
|
|
|
if (prev != UINT_MAX) {
|
|
timers[prev].next = next;
|
|
} else {
|
|
timerListHead[componentOffset] = next;
|
|
}
|
|
|
|
if (next != UINT_MAX) {
|
|
timers[next].prev = prev;
|
|
}
|
|
|
|
return next;
|
|
}
|
|
|
|
unsigned int moveTimerToList(unsigned int timer, unsigned int newComponentOffset) {
|
|
unsigned int currentComponentOffset = timers[timer].componentOffset;
|
|
unsigned int nextTimer = removeTimerFromList(timer, currentComponentOffset);
|
|
addTimerToList(timer, newComponentOffset);
|
|
return nextTimer;
|
|
}
|
|
|
|
/* Trigger a tick of the given component offset, to be called from system timers */
|
|
void tick(unsigned int componentOffset) {
|
|
//printf("Tick for %d\n", componentOffset);
|
|
|
|
/* Iterate this list, decrementing the timer components */
|
|
unsigned int timerIterator = timerListHead[componentOffset];
|
|
|
|
while (timerIterator != UINT_MAX) {
|
|
//printf("Iterating timer %d\n", timerIterator);
|
|
|
|
/* This timer needs to move to a higher precision list, or trigger */
|
|
if (!--timers[timerIterator].components[componentOffset]) {
|
|
|
|
/* Seek to next non-null component or the 0th component */
|
|
unsigned int nextComponentOffsetForTimer = componentOffset;
|
|
while (nextComponentOffsetForTimer && timers[timerIterator].components[nextComponentOffsetForTimer] == 0) {
|
|
nextComponentOffsetForTimer--;
|
|
}
|
|
|
|
/* Here we either have a new list to join or we trigger the timer here and now */
|
|
if (timers[timerIterator].components[nextComponentOffsetForTimer]) {
|
|
/* This should return the next timerIterator */
|
|
timerIterator = moveTimerToList(timerIterator, nextComponentOffsetForTimer);
|
|
} else {
|
|
/* This callback must not modify the list (but we can handle that later!) */
|
|
timerCallbacks[timerIterator]();
|
|
|
|
/* If the timer itself is removed in the above callback, below removal will fail */
|
|
|
|
/* And remove the timer (this should return the next timerIterator) */
|
|
timerIterator = removeTimerFromList(timerIterator, componentOffset);
|
|
}
|
|
} else {
|
|
timerIterator = timers[timerIterator].next;
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned int setTimeout_(void (*cb)(), unsigned int ms) {
|
|
/* Allocate free timer */
|
|
unsigned int timer = allocateTimer();
|
|
|
|
/* Divide given ms in components */
|
|
unsigned int biggestSetComponent = 0;
|
|
timers[timer].overshootMs = divideComponents(timers[timer].components, &biggestSetComponent, ms);
|
|
|
|
//printf("Overshoot by %u ms\n", timers[timer].overshootMs);
|
|
//printf("Biggest set component is %u\n", biggestSetComponent);
|
|
|
|
/* Add the timer to the list of the highest component */
|
|
addTimerToList(timer, biggestSetComponent);
|
|
|
|
/* Set the callback */
|
|
timerCallbacks[timer] = cb;
|
|
|
|
return timer;
|
|
}
|
|
|
|
void clearTimeout_(unsigned int timer) {
|
|
/* Unlink the timer from its list */
|
|
removeTimerFromList(timer, timers[timer].componentOffset);
|
|
|
|
/* Put the timer into free timer circle buffer */
|
|
freeTimer(timer);
|
|
} |