Laika/lib/src/core/ltask.c

125 lines
3.5 KiB
C

#include "core/ltask.h"
#include "core/lmem.h"
/* this is the only reason C11 support is needed, i cba to write windows/linux specific stuff to get
the current time in ms also side note: microsoft? more like micropenis */
long laikaT_getTime()
{
struct timespec ts;
timespec_get(&ts, TIME_UTC);
return ts.tv_sec * 1000 +
ts.tv_nsec / 1000000; /* convert time (seconds & nanoseconds) to milliseconds */
}
void laikaT_initTaskService(struct sLaika_taskService *service)
{
service->headTask = NULL;
}
void laikaT_cleanTaskService(struct sLaika_taskService *service)
{
struct sLaika_task *curr = service->headTask, *last;
/* walk though tasks, freeing all */
while (curr != NULL) {
last = curr;
curr = curr->next;
laikaM_free(last);
}
}
void scheduleTask(struct sLaika_taskService *service, struct sLaika_task *task)
{
struct sLaika_task *curr = service->headTask, *last = NULL;
task->scheduled = laikaT_getTime() + task->delta;
/* search list for task for which we're scheduled before */
while (curr != NULL && curr->scheduled < task->scheduled) {
last = curr;
curr = curr->next;
}
/* if we stopped at the first head item, set it */
if (curr == service->headTask) {
task->next = service->headTask;
service->headTask = task;
} else {
/* add to list */
task->next = curr;
if (last)
last->next = task;
}
}
void unscheduleTask(struct sLaika_taskService *service, struct sLaika_task *task)
{
struct sLaika_task *curr = service->headTask, *last = NULL;
if (task == service->headTask) { /* if task is root, set root to next */
service->headTask = task->next;
} else {
/* find in list */
while (curr != task) {
last = curr;
curr = curr->next;
}
/* unlink */
last->next = task->next;
task->next = NULL;
}
}
struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta,
taskCallback callback, void *uData)
{
struct sLaika_task *task = laikaM_malloc(sizeof(struct sLaika_task));
task->callback = callback;
task->uData = uData;
task->delta = delta;
task->next = NULL;
scheduleTask(service, task);
return task;
}
void laikaT_delTask(struct sLaika_taskService *service, struct sLaika_task *task)
{
unscheduleTask(service, task);
laikaM_free(task);
}
void laikaT_pollTasks(struct sLaika_taskService *service)
{
struct sLaika_task *last, *curr = service->headTask;
clock_t currTick = laikaT_getTime();
/* run each task, list is already sorted from closest scheduled task to furthest */
while (curr != NULL &&
curr->scheduled <= currTick) { /* if scheduled time is greater than currTime, all events
that follow are also not scheduled yet */
/* walk to next task */
last = curr;
curr = curr->next;
/* reset task timer */
unscheduleTask(service, last);
scheduleTask(service, last);
/* dispatch task callback */
last->callback(service, last, currTick, last->uData);
}
}
/* will return the delta time in ms till the next event. -1 for no tasks scheduled */
int laikaT_timeTillTask(struct sLaika_taskService *service)
{
if (service->headTask) {
int pause = service->headTask->scheduled - laikaT_getTime();
return (pause > 0) ? pause : 0;
} else
return -1; /* no tasks scheduled */
}