mirror of
https://github.com/Hizenberg469/WheelTimer.git
synced 2026-04-19 18:52:22 +03:00
Added Timer Library
This commit is contained in:
213
WheelTimer/libtimer/timerExample.c
Normal file
213
WheelTimer/libtimer/timerExample.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: timerExample.c
|
||||
*
|
||||
* Description: This file demonstrates the use of POSIX Timer routines
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 10/12/2020 11:25:06 AM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: ABHISHEK SAGAR (), sachinites@gmail.com
|
||||
* Organization: Juniper Networks
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Example */
|
||||
|
||||
typedef struct pair_{
|
||||
|
||||
int a;
|
||||
int b;
|
||||
} pair_t;
|
||||
|
||||
pair_t pair = { 10, 20 };
|
||||
|
||||
/* Define the structure which will be passed as an
|
||||
* argument to the timer callback function, We do this
|
||||
* to have more control over the timer*/
|
||||
typedef struct timer_user_arg_{
|
||||
|
||||
void *user_arg;
|
||||
size_t user_arg_size;
|
||||
timer_t *timer;
|
||||
uint32_t counter;
|
||||
} timer_user_arg_t;
|
||||
|
||||
typedef struct timer_user_arg_ Timer_t;
|
||||
|
||||
unsigned long
|
||||
get_time_remaining_in_mill_sec(
|
||||
struct timespec *time){
|
||||
|
||||
unsigned long milli_sec = 0;
|
||||
|
||||
milli_sec = time->tv_sec * 1000;
|
||||
milli_sec += time->tv_nsec / 1000000;
|
||||
return milli_sec;
|
||||
}
|
||||
|
||||
/* The Timer callback function which will be called every
|
||||
* time the timer expires. The signature of the function would be :
|
||||
* void <fn-name>(union sigval)
|
||||
* */
|
||||
void
|
||||
timer_callback(union sigval arg){
|
||||
|
||||
/* Extract the user data structure*/
|
||||
timer_user_arg_t *timer_user_arg =
|
||||
(timer_user_arg_t *) (arg.sival_ptr);
|
||||
|
||||
pair_t *pair = (pair_t *)(timer_user_arg->user_arg);
|
||||
/*
|
||||
* Timer is also passed as an argumeent to the timer
|
||||
* handler routine so that we can change the properties
|
||||
* of the timer from within the handler itself
|
||||
* */
|
||||
timer_t *timer = timer_user_arg->timer;
|
||||
|
||||
/* Get remaining time in next timer expiry */
|
||||
struct itimerspec remaining_time;
|
||||
memset(&remaining_time, 0, sizeof(struct itimerspec));
|
||||
|
||||
int rc = timer_gettime(*timer, &remaining_time);
|
||||
|
||||
printf("Timer = %p, Expiry Remaining time = %ld msec,"
|
||||
" pair : [%d, %d], invocation no = %u, overrun = %d\n",
|
||||
timer, get_time_remaining_in_mill_sec(&remaining_time.it_value),
|
||||
pair->a, pair->b, timer_user_arg->counter,
|
||||
timer_getoverrun(*timer));
|
||||
|
||||
timer_user_arg->counter++;
|
||||
|
||||
/* Let us kill the timer when it is invoked for 10 times */
|
||||
if(timer_user_arg->counter == 10){
|
||||
|
||||
rc = timer_delete(*timer); /* Now timer wont fire 11th time */
|
||||
|
||||
if(rc < 0) {
|
||||
|
||||
printf("Error in Timer Deletion, errno = %d\n", errno);
|
||||
exit(0);
|
||||
}
|
||||
/* Free up all the memory/resources */
|
||||
free(timer_user_arg->timer);
|
||||
free(timer_user_arg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
timer_demo(){
|
||||
|
||||
int ret;
|
||||
timer_t *timer;
|
||||
struct sigevent evp;
|
||||
|
||||
/* You can take it as a local variable if you
|
||||
* wish, in that case we will not free it in
|
||||
* timer handler fn */
|
||||
timer = calloc(1, sizeof(timer_t));
|
||||
|
||||
/* evp variable is used to setup timer properties*/
|
||||
memset(&evp, 0, sizeof(struct sigevent));
|
||||
|
||||
/* Fill the the user defined data structure.
|
||||
* When timer expires, this will be passed as
|
||||
* argument to the timer fn handler */
|
||||
timer_user_arg_t *timer_user_arg =
|
||||
calloc(1, sizeof(timer_user_arg_t));
|
||||
timer_user_arg->user_arg = (void *)&pair;
|
||||
timer_user_arg->user_arg_size = sizeof(pair_t);
|
||||
timer_user_arg->timer = timer;
|
||||
timer_user_arg->counter = 0;
|
||||
|
||||
evp.sigev_value.sival_ptr = (void *)timer_user_arg;
|
||||
|
||||
/* On timer Expiry, We want kernel to launch the
|
||||
* timer handler routine in a separate thread context */
|
||||
evp.sigev_notify = SIGEV_THREAD;
|
||||
|
||||
/* Register the timer hander routine. This routine shall
|
||||
* be invoked when timer expires*/
|
||||
evp.sigev_notify_function = timer_callback;
|
||||
|
||||
/* Create a timer. It is just a timer initialization, Timer
|
||||
* is not fired (Alarmed) */
|
||||
ret = timer_create (CLOCK_REALTIME,
|
||||
&evp,
|
||||
timer);
|
||||
|
||||
if ( ret < 0) {
|
||||
|
||||
printf("Timer Creation failed, errno = %d\n", errno);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Let us say, I want to start the timer after 5 seconds from now
|
||||
* (now = say, t = 0) and once the 5 seconds elapsed, i
|
||||
* want the timer to keep firing after every 2 seconds repeatedly.
|
||||
* It simply mean that - if i start the timer as time t = 0, then
|
||||
* timer handler routine (timer_callback) shall be called at t = 5,
|
||||
* t = 7, t = 9 ... so on*/
|
||||
|
||||
/* Let us setup the time intervals */
|
||||
|
||||
struct itimerspec ts;
|
||||
|
||||
/* I want the timer to fire for the first time after 5 seconds
|
||||
* and 0 nano seconds*/
|
||||
ts.it_value.tv_sec = 5;
|
||||
ts.it_value.tv_nsec = 0;
|
||||
|
||||
/* After the timer has fired for the first time, i want the timer
|
||||
* to repeatedly fire after every 2 sec and 0 nano sec */
|
||||
ts.it_interval.tv_sec = 2;
|
||||
ts.it_interval.tv_nsec = 0;
|
||||
|
||||
/* Now start the timer*/
|
||||
ret = timer_settime (*timer,
|
||||
0,
|
||||
&ts,
|
||||
NULL);
|
||||
|
||||
if ( ret < 0) {
|
||||
|
||||
printf("Timer Start failed, errno = %d\n", errno);
|
||||
exit(0);
|
||||
}
|
||||
pause();
|
||||
}
|
||||
|
||||
/* Returns NULL in timer creation fails, else
|
||||
* return a pointer to Timer object*/
|
||||
Timer_t*
|
||||
setup_timer(
|
||||
void (*)(void *, size_t), /* Timer Callback */
|
||||
unsigned long long, /* First expiration time interval in msec */
|
||||
bool, /* true if timer is repeatable, false for one-shot */
|
||||
unsigned long long, /* Subsequent expiration time interval in msec */
|
||||
void *arg, /* Arg to timer callback */
|
||||
size_t arg_size); /* Arg memory size */
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv){
|
||||
|
||||
timer_demo();
|
||||
pause();
|
||||
return 0;
|
||||
}
|
||||
246
WheelTimer/libtimer/timerlib.c
Normal file
246
WheelTimer/libtimer/timerlib.c
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: timerExample.c
|
||||
*
|
||||
* Description: This file demonstrates the use of POSIX Timer routines
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 10/12/2020 11:25:06 AM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: ABHISHEK SAGAR (), sachinites@gmail.com
|
||||
* Organization: Juniper Networks
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include "timerlib.h"
|
||||
|
||||
static unsigned long
|
||||
timespec_to_millisec(
|
||||
struct timespec *time){
|
||||
|
||||
unsigned long milli_sec = 0;
|
||||
|
||||
milli_sec = time->tv_sec * 1000;
|
||||
milli_sec += time->tv_nsec / 1000000;
|
||||
return milli_sec;
|
||||
}
|
||||
|
||||
static void
|
||||
timer_fill_itimerspec(struct timespec *ts,
|
||||
unsigned long msec) {
|
||||
|
||||
memset(ts, 0, sizeof(struct timespec));
|
||||
|
||||
if(!msec) return;
|
||||
|
||||
unsigned long sec = msec/1000;
|
||||
ts->tv_sec = sec;
|
||||
|
||||
unsigned long remaining_msec = msec % 1000;
|
||||
|
||||
ts->tv_nsec = remaining_msec * (1000000);
|
||||
}
|
||||
|
||||
static void
|
||||
timer_callback_wrapper(union sigval arg){
|
||||
|
||||
Timer_t *timer = (Timer_t *)(arg.sival_ptr);
|
||||
timer->invocation_counter++;
|
||||
if(timer->thresdhold &&
|
||||
(timer->invocation_counter > timer->thresdhold)){
|
||||
cancel_timer(timer);
|
||||
return;
|
||||
}
|
||||
(timer->cb)(timer, timer->user_arg);
|
||||
}
|
||||
|
||||
|
||||
/* Returns NULL in timer creation fails, else
|
||||
* return a pointer to Timer object*/
|
||||
Timer_t*
|
||||
setup_timer(
|
||||
void (*timer_cb)(Timer_t*, void *), /* Timer Callback with user data*/
|
||||
unsigned long exp_timer, /* First expiration time interval in msec */
|
||||
unsigned long sec_exp_timer, /* Subsequent expiration time interval in msec */
|
||||
uint32_t threshold, /* Max no of expirations, 0 for infinite*/
|
||||
void *user_arg){ /* Arg to timer callback */
|
||||
|
||||
|
||||
Timer_t *timer = calloc(1, sizeof(Timer_t));
|
||||
timer->posix_timer = calloc(1, sizeof(timer_t));
|
||||
|
||||
timer->user_arg = user_arg;
|
||||
timer->exp_timer = exp_timer;
|
||||
timer->sec_exp_timer = sec_exp_timer;
|
||||
timer->cb = timer_cb;
|
||||
timer->thresdhold = threshold;
|
||||
timer->timer_state = TIMER_INIT;
|
||||
|
||||
/* Sanity checks */
|
||||
assert(timer->cb); /* Mandatory */
|
||||
|
||||
|
||||
struct sigevent evp;
|
||||
memset(&evp, 0, sizeof(struct sigevent));
|
||||
|
||||
evp.sigev_value.sival_ptr = (void *)(timer);
|
||||
evp.sigev_notify = SIGEV_THREAD;
|
||||
evp.sigev_notify_function = timer_callback_wrapper;
|
||||
|
||||
int rc = timer_create (CLOCK_REALTIME,
|
||||
&evp, timer->posix_timer);
|
||||
|
||||
assert(rc >= 0);
|
||||
|
||||
timer_fill_itimerspec(&timer->ts.it_value, timer->exp_timer);
|
||||
timer_fill_itimerspec(&timer->ts.it_interval, timer->sec_exp_timer);
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
void
|
||||
start_timer(Timer_t *timer){
|
||||
|
||||
int rc;
|
||||
|
||||
rc = timer_settime(*(timer->posix_timer), 0, &timer->ts, NULL);
|
||||
assert(rc >= 0);
|
||||
timer->timer_state = TIMER_RUNNING;
|
||||
}
|
||||
|
||||
void
|
||||
delete_timer(Timer_t *timer){
|
||||
|
||||
int rc;
|
||||
rc = timer_delete(*(timer->posix_timer));
|
||||
assert(rc >= 0);
|
||||
free(timer->posix_timer);
|
||||
timer->posix_timer = NULL;
|
||||
timer->user_arg = NULL; /* User arg need to be freed by Appln */
|
||||
timer->timer_state = TIMER_DELETED;
|
||||
}
|
||||
|
||||
void
|
||||
cancel_timer(Timer_t *timer){
|
||||
|
||||
if(timer->timer_state == TIMER_INIT ||
|
||||
timer->timer_state == TIMER_DELETED) {
|
||||
|
||||
return; /* No-Operation */
|
||||
}
|
||||
|
||||
/* Only Paused or running timer can be cancelled */
|
||||
timer_fill_itimerspec(&timer->ts.it_value, 0);
|
||||
timer_fill_itimerspec(&timer->ts.it_interval, 0);
|
||||
timer->time_remaining = 0;
|
||||
start_timer(timer);
|
||||
timer->timer_state = TIMER_CANCELLED;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pause_timer(Timer_t *timer){
|
||||
|
||||
assert(timer->timer_state == TIMER_RUNNING);
|
||||
|
||||
timer->time_remaining =
|
||||
timer_get_time_remaining_in_mill_sec(timer);
|
||||
|
||||
timer_fill_itimerspec(&timer->ts.it_value, 0);
|
||||
|
||||
/* Do not reset the interval */
|
||||
//timer_fill_itimerspec(&timer->ts.it_interval, 0);
|
||||
|
||||
start_timer(timer);
|
||||
|
||||
timer->timer_state = TIMER_PAUSED;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
resume_timer(Timer_t *timer){
|
||||
|
||||
assert(timer->timer_state == TIMER_PAUSED);
|
||||
|
||||
timer_fill_itimerspec(&timer->ts.it_value, timer->time_remaining);
|
||||
timer->time_remaining = 0;
|
||||
start_timer(timer);
|
||||
timer->timer_state = TIMER_RUNNING;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
timer_get_time_remaining_in_mill_sec(Timer_t *timer){
|
||||
|
||||
struct itimerspec remaining_time;
|
||||
|
||||
switch(timer->timer_state){
|
||||
|
||||
case TIMER_INIT:
|
||||
break;
|
||||
case TIMER_DELETED:
|
||||
return ~0;
|
||||
case TIMER_PAUSED:
|
||||
break;
|
||||
case TIMER_CANCELLED:
|
||||
return ~0;
|
||||
case TIMER_RUNNING:
|
||||
break;
|
||||
default : ;
|
||||
}
|
||||
|
||||
memset(&remaining_time, 0, sizeof(struct itimerspec));
|
||||
|
||||
timer_gettime(*timer->posix_timer, &remaining_time);
|
||||
|
||||
return timespec_to_millisec(&remaining_time.it_value);
|
||||
}
|
||||
|
||||
void
|
||||
restart_timer(Timer_t *timer){
|
||||
|
||||
if(timer->timer_state != TIMER_PAUSED ||
|
||||
timer->timer_state != TIMER_RUNNING) {
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
cancel_timer(timer);
|
||||
|
||||
timer_fill_itimerspec(&timer->ts.it_value, timer->exp_timer);
|
||||
timer_fill_itimerspec(&timer->ts.it_interval, timer->sec_exp_timer);
|
||||
timer->invocation_counter = 0;
|
||||
timer->time_remaining = 0;
|
||||
start_timer(timer);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
reschedule_timer(Timer_t *timer,
|
||||
unsigned long exp_ti,
|
||||
unsigned long sec_exp_ti){
|
||||
|
||||
if(timer->timer_state == TIMER_DELETED) assert(0);
|
||||
|
||||
if(timer->timer_state != TIMER_CANCELLED) {
|
||||
cancel_timer(timer);
|
||||
}
|
||||
|
||||
timer->exp_timer = exp_ti;
|
||||
timer->sec_exp_timer = sec_exp_ti;
|
||||
timer->invocation_counter = 0;
|
||||
timer_fill_itimerspec(&timer->ts.it_value, exp_ti);
|
||||
timer_fill_itimerspec(&timer->ts.it_interval, sec_exp_ti);
|
||||
timer->time_remaining = 0;
|
||||
start_timer(timer);
|
||||
timer->timer_state = TIMER_RUNNING;
|
||||
}
|
||||
|
||||
99
WheelTimer/libtimer/timerlib.h
Normal file
99
WheelTimer/libtimer/timerlib.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: timerlib.h
|
||||
*
|
||||
* Description: This file is a wrapper over Timer POSIX Timer library
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 10/12/2020 01:47:16 PM
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: ABHISHEK SAGAR (), sachinites@gmail.com
|
||||
* Organization: Juniper Networks
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __TIMER_WRAP__
|
||||
#define __TIMER_WRAP__
|
||||
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum{
|
||||
|
||||
TIMER_INIT,
|
||||
TIMER_DELETED,
|
||||
TIMER_PAUSED,
|
||||
TIMER_CANCELLED,
|
||||
TIMER_RUNNING,
|
||||
} TIMER_STATE_T;
|
||||
|
||||
typedef struct Timer_{
|
||||
|
||||
/* Timer config */
|
||||
timer_t *posix_timer;
|
||||
void *user_arg;
|
||||
unsigned long exp_timer; /* in milli-sec */
|
||||
unsigned long sec_exp_timer; /* in milli-sec */
|
||||
uint32_t thresdhold; /* No of times to invoke the timer callback */
|
||||
void (*cb)(struct Timer_ *, void *); /* Timer Callback */
|
||||
|
||||
/* place holder value to store
|
||||
* dynamic attributes of timer */
|
||||
unsigned long time_remaining; /* Time left for paused timer for next expiration */
|
||||
uint32_t invocation_counter;
|
||||
struct itimerspec ts;
|
||||
TIMER_STATE_T timer_state;
|
||||
} Timer_t;
|
||||
|
||||
/* Returns NULL in timer creation fails, else
|
||||
* return a pointer to Timer object*/
|
||||
Timer_t*
|
||||
setup_timer(
|
||||
/* Timer Callback with user data and user size*/
|
||||
void (*)(Timer_t*, void *),
|
||||
/* First expiration time interval in msec */
|
||||
unsigned long,
|
||||
/* Subsequent expiration time interval in msec */
|
||||
unsigned long,
|
||||
/* Max no of expirations, 0 for infinite*/
|
||||
uint32_t,
|
||||
/* Arg to timer callback */
|
||||
void *);
|
||||
|
||||
void
|
||||
start_timer(Timer_t *timer);
|
||||
|
||||
void
|
||||
delete_timer(Timer_t *timer);
|
||||
|
||||
void
|
||||
cancel_timer(Timer_t *timer);
|
||||
|
||||
void
|
||||
pause_timer(Timer_t *timer);
|
||||
|
||||
void
|
||||
resume_timer(Timer_t *timer);
|
||||
|
||||
int
|
||||
execute_timer(Timer_t *timer, TIMER_STATE_T action);
|
||||
|
||||
/* get remaining time in msec */
|
||||
unsigned long
|
||||
timer_get_time_remaining_in_mill_sec(Timer_t *timer);
|
||||
|
||||
void
|
||||
restart_timer(Timer_t *timer);
|
||||
|
||||
int
|
||||
reschedule_timer(Timer_t *timer,
|
||||
unsigned long exp_ti,
|
||||
unsigned long sec_exp_ti);
|
||||
#endif /* __TIMER_WRAP__ */
|
||||
Reference in New Issue
Block a user