mirror of
https://github.com/rtbrick/bngblaster.git
synced 2024-05-06 15:54:57 +00:00
109 lines
3.0 KiB
C
109 lines
3.0 KiB
C
/*
|
|
* A O(1) Timer library
|
|
*
|
|
* Hannes Gredler, July 2020
|
|
*
|
|
* Copyright (C) 2020-2023, RtBrick, Inc.
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#ifndef __COMMON_TIMER_H__
|
|
#define __COMMON_TIMER_H__
|
|
#include "common.h"
|
|
|
|
#define MSEC 1000000 /* 1 million nanoseconds == 1 msec */
|
|
#define SEC 1000000000 /* 1 billion nanoseconds == 1 sec */
|
|
|
|
/* Top level data structure for timers. */
|
|
typedef struct timer_root_
|
|
{
|
|
CIRCLEQ_HEAD(timer_bucket_root_, timer_bucket_ ) timer_bucket_qhead; /* Bucket list */
|
|
CIRCLEQ_HEAD(timer_gc_root_, timer_ ) timer_gc_qhead; /* Garbage collection list */
|
|
CIRCLEQ_HEAD(timer_change_root_, timer_ ) timer_change_qhead; /* Change timers list */
|
|
|
|
uint32_t buckets; /* # of buckets hanging off */
|
|
uint32_t gc; /* # of timers waiting for GC */
|
|
|
|
} timer_root_s;
|
|
|
|
/* Group each like timers (e.g. all 100ms, 1s, 5s timers) into a timer bucket.
|
|
* All buckets hang off the timer root.
|
|
* Since time does not run backwards, timer insertion becomes a O(1) operation as one needs
|
|
* only to locate the appropriate bucket and insert at the tail of the per bucket queue. */
|
|
typedef struct timer_bucket_
|
|
{
|
|
CIRCLEQ_HEAD(timer_bucket_head_, timer_ ) timer_qhead; /* head of timers */
|
|
CIRCLEQ_ENTRY(timer_bucket_) timer_bucket_qnode; /* node in bucket list */
|
|
|
|
struct timer_root_ *timer_root; /* back pointer */
|
|
|
|
time_t sec;
|
|
long nsec;
|
|
|
|
uint32_t timers; /* # of timers hanging off this bucket */
|
|
} timer_bucket_s;
|
|
|
|
/* Timer which hangs off the bucket list. */
|
|
typedef struct timer_
|
|
{
|
|
CIRCLEQ_ENTRY(timer_) timer_qnode;
|
|
CIRCLEQ_ENTRY(timer_) timer_change_qnode;
|
|
struct timespec expire; /* expiration interval */
|
|
struct timespec *timestamp;
|
|
struct timer_bucket_ *timer_bucket; /* back pointer */
|
|
struct timer_ **ptimer; /* where this timer pointer gets stored */
|
|
void *data; /* misc. data */
|
|
void (*cb)(struct timer_ *); /* callback function. */
|
|
bool expired;
|
|
bool periodic; /* auto restart timer ? */
|
|
bool reset; /* reset reference/start time */
|
|
bool delete; /* timer has been deleted */
|
|
bool on_change_list; /* node is on change list */
|
|
bool no_smear; /* do not smear this timer */
|
|
char name[32];
|
|
} timer_s;
|
|
|
|
/* Public API */
|
|
|
|
void
|
|
timespec_add(struct timespec *, struct timespec *, struct timespec *);
|
|
|
|
void
|
|
timespec_sub(struct timespec *, struct timespec *, struct timespec *);
|
|
|
|
char *
|
|
timespec_format(struct timespec *x);
|
|
|
|
void
|
|
timer_smear_bucket(timer_root_s *, time_t, long);
|
|
|
|
void
|
|
timer_smear_all_buckets(timer_root_s *root);
|
|
|
|
void
|
|
timer_no_smear(timer_s *timer);
|
|
|
|
void
|
|
timer_del(timer_s *timer);
|
|
|
|
void
|
|
timer_add(timer_root_s *root, timer_s **ptimer, char *name,
|
|
time_t sec, long nsec,
|
|
void *data, void (*cb)(timer_s *));
|
|
|
|
void
|
|
timer_add_periodic(timer_root_s *root, timer_s **ptimer, char *name,
|
|
time_t sec, long nsec,
|
|
void *data, void (*cb)(timer_s *));
|
|
|
|
void
|
|
timer_walk(timer_root_s *root);
|
|
|
|
void
|
|
timer_init_root(timer_root_s *timer_root);
|
|
|
|
void
|
|
timer_flush_root(timer_root_s *timer_root);
|
|
|
|
#endif /* __TIMER_H__ */
|