176 lines
3.9 KiB
C
176 lines
3.9 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include "logger.h"
|
|
#include "fast_timer.h"
|
|
|
|
int fast_timer_init(FastTimer *timer, const int slot_count,
|
|
const int64_t current_time)
|
|
{
|
|
int bytes;
|
|
if (slot_count <= 0 || current_time <= 0) {
|
|
return EINVAL;
|
|
}
|
|
|
|
timer->slot_count = slot_count;
|
|
timer->base_time = current_time; //base time for slot 0
|
|
timer->current_time = current_time;
|
|
bytes = sizeof(FastTimerSlot) * slot_count;
|
|
timer->slots = (FastTimerSlot *)malloc(bytes);
|
|
if (timer->slots == NULL) {
|
|
return errno != 0 ? errno : ENOMEM;
|
|
}
|
|
memset(timer->slots, 0, bytes);
|
|
return 0;
|
|
}
|
|
|
|
void fast_timer_destroy(FastTimer *timer)
|
|
{
|
|
if (timer->slots != NULL) {
|
|
free(timer->slots);
|
|
timer->slots = NULL;
|
|
}
|
|
}
|
|
|
|
#define TIMER_GET_SLOT_INDEX(timer, expires) \
|
|
(((expires) - timer->base_time) % timer->slot_count)
|
|
|
|
#define TIMER_GET_SLOT_POINTER(timer, expires) \
|
|
(timer->slots + TIMER_GET_SLOT_INDEX(timer, expires))
|
|
|
|
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry)
|
|
{
|
|
FastTimerSlot *slot;
|
|
|
|
slot = TIMER_GET_SLOT_POINTER(timer, entry->expires >
|
|
timer->current_time ? entry->expires : timer->current_time);
|
|
entry->next = slot->head.next;
|
|
if (slot->head.next != NULL) {
|
|
slot->head.next->prev = entry;
|
|
}
|
|
entry->prev = &slot->head;
|
|
slot->head.next = entry;
|
|
return 0;
|
|
}
|
|
|
|
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
|
const int64_t new_expires)
|
|
{
|
|
if (new_expires == entry->expires) {
|
|
return 0;
|
|
}
|
|
|
|
if (new_expires < entry->expires) {
|
|
fast_timer_remove(timer, entry);
|
|
entry->expires = new_expires;
|
|
return fast_timer_add(timer, entry);
|
|
}
|
|
|
|
entry->rehash = TIMER_GET_SLOT_INDEX(timer, new_expires) !=
|
|
TIMER_GET_SLOT_INDEX(timer, entry->expires);
|
|
entry->expires = new_expires; //lazy move
|
|
return 0;
|
|
}
|
|
|
|
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry)
|
|
{
|
|
if (entry->prev == NULL) {
|
|
return ENOENT; //already removed
|
|
}
|
|
|
|
if (entry->next != NULL) {
|
|
entry->next->prev = entry->prev;
|
|
entry->prev->next = entry->next;
|
|
entry->next = NULL;
|
|
}
|
|
else {
|
|
entry->prev->next = NULL;
|
|
}
|
|
|
|
entry->prev = NULL;
|
|
return 0;
|
|
}
|
|
|
|
FastTimerSlot *fast_timer_slot_get(FastTimer *timer, const int64_t current_time)
|
|
{
|
|
if (timer->current_time >= current_time) {
|
|
return NULL;
|
|
}
|
|
|
|
return TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
|
|
}
|
|
|
|
int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
|
|
FastTimerEntry *head)
|
|
{
|
|
FastTimerSlot *slot;
|
|
FastTimerEntry *entry;
|
|
FastTimerEntry *first;
|
|
FastTimerEntry *last;
|
|
FastTimerEntry *tail;
|
|
int count;
|
|
|
|
head->prev = NULL;
|
|
head->next = NULL;
|
|
if (timer->current_time >= current_time) {
|
|
return 0;
|
|
}
|
|
|
|
first = NULL;
|
|
last = NULL;
|
|
tail = head;
|
|
count = 0;
|
|
while (timer->current_time < current_time) {
|
|
slot = TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
|
|
entry = slot->head.next;
|
|
while (entry != NULL) {
|
|
if (entry->expires >= current_time) { //not expired
|
|
if (first != NULL) {
|
|
first->prev->next = entry;
|
|
entry->prev = first->prev;
|
|
|
|
tail->next = first;
|
|
first->prev = tail;
|
|
tail = last;
|
|
first = NULL;
|
|
}
|
|
if (entry->rehash) {
|
|
last = entry;
|
|
entry = entry->next;
|
|
|
|
last->rehash = false;
|
|
fast_timer_remove(timer, last);
|
|
fast_timer_add(timer, last);
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
count++;
|
|
if (first == NULL) {
|
|
first = entry;
|
|
}
|
|
}
|
|
last = entry;
|
|
entry = entry->next;
|
|
}
|
|
|
|
if (first != NULL) {
|
|
first->prev->next = NULL;
|
|
|
|
tail->next = first;
|
|
first->prev = tail;
|
|
tail = last;
|
|
first = NULL;
|
|
}
|
|
}
|
|
|
|
if (count > 0) {
|
|
tail->next = NULL;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|