mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
88 lines
2.4 KiB
C
88 lines
2.4 KiB
C
#include <kernel/itimer.h>
|
|
#include <logging.h>
|
|
|
|
static void itimer_dpc(context_t *context, dpcarg_t arg) {
|
|
itimer_t *itimer = arg;
|
|
spinlock_acquire(&itimer->lock);
|
|
if (itimer->paused)
|
|
goto leave;
|
|
|
|
itimer->remainingus = itimer->repeatus ? itimer->repeatus : 0;
|
|
itimer->paused = itimer->repeatus == 0;
|
|
itimer->fn(context, itimer->arg);
|
|
if (itimer->repeatus) {
|
|
timer_insert(current_cpu()->timer, &itimer->entry, itimer_dpc, itimer, itimer->remainingus, false);
|
|
}
|
|
|
|
leave:
|
|
spinlock_release(&itimer->lock);
|
|
}
|
|
|
|
void itimer_init(itimer_t *itimer, dpcfn_t fn, dpcarg_t arg) {
|
|
memset(itimer, 0, sizeof(itimer_t));
|
|
itimer->fn = fn;
|
|
itimer->arg = arg;
|
|
itimer->paused = true;
|
|
SPINLOCK_INIT(itimer->lock);
|
|
}
|
|
|
|
void itimer_pause(itimer_t *itimer, uintmax_t *remainingus, uintmax_t *repeatus) {
|
|
bool intstatus = interrupt_set(false);
|
|
spinlock_acquire(&itimer->lock);
|
|
|
|
|
|
while (itimer->cpu && itimer->cpu != current_cpu()) {
|
|
// schedule on the itimer cpu
|
|
spinlock_release(&itimer->lock);
|
|
sched_reschedule_on_cpu(itimer->cpu, false);
|
|
spinlock_acquire(&itimer->lock);
|
|
}
|
|
|
|
if (itimer->paused)
|
|
goto cleanup;
|
|
|
|
itimer->cpu = NULL;
|
|
itimer->remainingus = timer_remove(current_cpu()->timer, &itimer->entry);
|
|
if (itimer->remainingus == 0) {
|
|
// while we were running in the cpu, the timer fired.
|
|
// the dpc won't be handled because the timer entry
|
|
// has already been removed from the queue.
|
|
// this will be handled as a ''timer was one microsecond away from firing''
|
|
// situation as its the cleanest way of doing this.
|
|
itimer->remainingus = 1;
|
|
}
|
|
itimer->paused = true;
|
|
cleanup:
|
|
|
|
spinlock_release(&itimer->lock);
|
|
interrupt_set(intstatus);
|
|
if (remainingus)
|
|
*remainingus = itimer->remainingus;
|
|
if (repeatus)
|
|
*repeatus = itimer->repeatus;
|
|
}
|
|
|
|
void itimer_set(itimer_t *itimer, uintmax_t timerus, uintmax_t repeatus) {
|
|
bool intstatus = interrupt_set(false);
|
|
spinlock_acquire(&itimer->lock);
|
|
|
|
itimer->remainingus = timerus;
|
|
itimer->repeatus = repeatus;
|
|
|
|
spinlock_release(&itimer->lock);
|
|
interrupt_set(intstatus);
|
|
}
|
|
|
|
void itimer_resume(itimer_t *itimer) {
|
|
bool intstatus = interrupt_set(false);
|
|
spinlock_acquire(&itimer->lock);
|
|
|
|
__assert(itimer->paused && itimer->remainingus);
|
|
itimer->cpu = current_cpu();
|
|
itimer->paused = false;
|
|
timer_insert(current_cpu()->timer, &itimer->entry, itimer_dpc, itimer, itimer->remainingus, false);
|
|
|
|
spinlock_release(&itimer->lock);
|
|
interrupt_set(intstatus);
|
|
}
|