mirror of
https://github.com/Hizenberg469/WheelTimer.git
synced 2026-04-19 18:52:22 +03:00
timerExampleDemo1.c First Demo
This commit is contained in:
143
WheelTimer/libtimer/Course/timerExampleDemo1.c
Normal file
143
WheelTimer/libtimer/Course/timerExampleDemo1.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
/* To work with the posix timers
|
||||
* below two hdr files are necessary
|
||||
**/
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
|
||||
/* Other standard hdr files we would need */
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <unistd.h> /* for pause() */
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static void
|
||||
print_current_system_time(){
|
||||
|
||||
time_t t;
|
||||
time(&t); /* Get the current system time */
|
||||
|
||||
/* Print the current system time,
|
||||
* Will insert one \n character */
|
||||
printf("%s ",ctime(&t));
|
||||
}
|
||||
|
||||
/* Example */
|
||||
typedef struct pair_{
|
||||
|
||||
int a;
|
||||
int b;
|
||||
} pair_t;
|
||||
|
||||
pair_t pair = { 10, 20 };
|
||||
|
||||
/* 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){
|
||||
|
||||
print_current_system_time();
|
||||
|
||||
pair_t *pair = (pair_t *) arg.sival_ptr; /*Extract the user data structure*/
|
||||
|
||||
printf("pair : [%u %u]\n", pair->a, pair->b);
|
||||
}
|
||||
|
||||
void
|
||||
timer_demo(){
|
||||
|
||||
int ret;
|
||||
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_t timer;
|
||||
memset(&timer, 0, 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 callback handler */
|
||||
evp.sigev_value.sival_ptr = (void *)&pair;
|
||||
|
||||
/* 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 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;
|
||||
|
||||
ts.it_interval.tv_sec = 0;
|
||||
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);
|
||||
}
|
||||
else {
|
||||
print_current_system_time();
|
||||
printf("Timer Alarmed Successfully\n");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv){
|
||||
|
||||
timer_demo();
|
||||
pause();
|
||||
return 0;
|
||||
}
|
||||
338
WheelTimer/libtimer/WheelTimer/WheelTimer.c
Normal file
338
WheelTimer/libtimer/WheelTimer/WheelTimer.c
Normal file
@@ -0,0 +1,338 @@
|
||||
#include "WheelTimer.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define TH_JOINABLE 1
|
||||
#define TH_DETACHED 0
|
||||
|
||||
|
||||
int
|
||||
insert_wt_elem_in_slot(void *data1, void *data2){
|
||||
|
||||
wheel_timer_elem_t *wt_elem1 = (wheel_timer_elem_t *)data1;
|
||||
wheel_timer_elem_t *wt_elem2 = (wheel_timer_elem_t *)data2;
|
||||
|
||||
if(wt_elem1->execute_cycle_no < wt_elem2->execute_cycle_no)
|
||||
return -1;
|
||||
|
||||
if(wt_elem1->execute_cycle_no > wt_elem2->execute_cycle_no)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
wheel_timer_t*
|
||||
init_wheel_timer(int wheel_size, int clock_tic_interval){
|
||||
wheel_timer_t *wt = calloc(1, sizeof(wheel_timer_t) +
|
||||
(wheel_size * sizeof(slotlist_t)));
|
||||
|
||||
wt->clock_tic_interval = clock_tic_interval;
|
||||
wt->wheel_size = wheel_size;
|
||||
|
||||
memset(&(wt->wheel_thread), 0, sizeof(wheel_timer_t));
|
||||
|
||||
int i = 0;
|
||||
for(; i < wheel_size; i++){
|
||||
init_glthread(WT_SLOTLIST_HEAD(wt, i));
|
||||
pthread_mutex_init(WT_SLOTLIST_MUTEX(wt, i), NULL);
|
||||
}
|
||||
wt->no_of_wt_elem = 0;
|
||||
return wt;
|
||||
}
|
||||
|
||||
static void
|
||||
process_wt_reschedule_slotlist(wheel_timer_t *wt){
|
||||
|
||||
glthread_t *curr;
|
||||
wheel_timer_elem_t *wt_elem;
|
||||
|
||||
WT_LOCK_SLOT_LIST(WT_GET_RESCHD_SLOTLIST(wt));
|
||||
if(WT_IS_SLOTLIST_EMPTY(WT_GET_RESCHD_SLOTLIST(wt))){
|
||||
WT_UNLOCK_SLOT_LIST(WT_GET_RESCHD_SLOTLIST(wt));
|
||||
return;
|
||||
}
|
||||
|
||||
ITERATE_GLTHREAD_BEGIN(WT_GET_RESCHD_SLOTLIST_HEAD(wt), curr){
|
||||
|
||||
wt_elem = glthread_reschedule_glue_to_wt_elem(curr);
|
||||
remove_glthread(&wt_elem->glue);
|
||||
wt_elem->slotlist_head = NULL;
|
||||
|
||||
switch(wt_elem->opcode){
|
||||
case WTELEM_CREATE:
|
||||
case WTELEM_RESCHED:
|
||||
{
|
||||
assert(wt_elem->app_callback);
|
||||
wt_elem->time_interval = wt_elem->new_time_interval;
|
||||
int absolute_slot_no = GET_WT_CURRENT_ABS_SLOT_NO(wt);
|
||||
int next_abs_slot_no = absolute_slot_no +
|
||||
(wt_elem->time_interval/wt->clock_tic_interval);
|
||||
int next_cycle_no = next_abs_slot_no / wt->wheel_size;
|
||||
int next_slot_no = next_abs_slot_no % wt->wheel_size;
|
||||
wt_elem->execute_cycle_no = next_cycle_no;
|
||||
wt_elem->slot_no = next_slot_no;
|
||||
glthread_priority_insert(WT_SLOTLIST_HEAD(wt, wt_elem->slot_no),
|
||||
&wt_elem->glue,
|
||||
insert_wt_elem_in_slot,
|
||||
(unsigned long)&((wheel_timer_elem_t *)0)->glue);
|
||||
wt_elem->slotlist_head = WT_SLOTLIST(wt, wt_elem->slot_no);
|
||||
remove_glthread(&wt_elem->reschedule_glue);
|
||||
wt_elem->N_scheduled++;
|
||||
if(wt_elem->opcode == WTELEM_CREATE){
|
||||
wt->no_of_wt_elem++;
|
||||
}
|
||||
wt_elem->opcode = WTELEM_SCHEDULED;
|
||||
}
|
||||
break;
|
||||
case WTELEM_DELETE:
|
||||
remove_glthread(&wt_elem->reschedule_glue);
|
||||
free_wheel_timer_element(wt_elem);
|
||||
wt->no_of_wt_elem--;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}ITERATE_GLTHREAD_END(WT_GET_RESCHD_SLOTLIST_HEAD(wt), curr)
|
||||
WT_UNLOCK_SLOT_LIST(WT_GET_RESCHD_SLOTLIST(wt));
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
wheel_fn(void *arg){
|
||||
|
||||
wheel_timer_t *wt = (wheel_timer_t *)arg;
|
||||
wheel_timer_elem_t *wt_elem = NULL;
|
||||
int absolute_slot_no = 0, i =0;
|
||||
slotlist_t *slot_list = NULL;
|
||||
glthread_t *curr;
|
||||
|
||||
while(1){
|
||||
|
||||
wt->current_clock_tic++;
|
||||
if(wt->current_clock_tic == wt->wheel_size){
|
||||
wt->current_clock_tic = 0;
|
||||
wt->current_cycle_no++;
|
||||
}
|
||||
|
||||
sleep(wt->clock_tic_interval);
|
||||
|
||||
slot_list = WT_SLOTLIST(wt, wt->current_clock_tic);
|
||||
absolute_slot_no = GET_WT_CURRENT_ABS_SLOT_NO(wt);
|
||||
|
||||
ITERATE_GLTHREAD_BEGIN(&slot_list->slots, curr){
|
||||
|
||||
wt_elem = glthread_to_wt_elem(curr);
|
||||
|
||||
/*Check if R == r*/
|
||||
if(wt->current_cycle_no == wt_elem->execute_cycle_no){
|
||||
/*Invoke the application event through fn pointer as below*/
|
||||
wt_elem->app_callback(wt_elem->arg, wt_elem->arg_size);
|
||||
|
||||
/* After invocation, check if the event needs to be rescheduled again
|
||||
* in future*/
|
||||
if(wt_elem->is_recurrence){
|
||||
|
||||
/*relocate Or reschedule to the next slot*/
|
||||
int next_abs_slot_no = absolute_slot_no +
|
||||
(wt_elem->time_interval/wt->clock_tic_interval);
|
||||
int next_cycle_no = next_abs_slot_no / wt->wheel_size;
|
||||
int next_slot_no = next_abs_slot_no % wt->wheel_size;
|
||||
wt_elem->execute_cycle_no = next_cycle_no;
|
||||
remove_glthread(&wt_elem->glue);
|
||||
glthread_priority_insert(WT_SLOTLIST_HEAD(wt, next_slot_no), &wt_elem->glue,
|
||||
insert_wt_elem_in_slot,
|
||||
(unsigned long)&((wheel_timer_elem_t *)0)->glue);
|
||||
wt_elem->slotlist_head = WT_SLOTLIST(wt, next_slot_no);
|
||||
wt_elem->slot_no = next_slot_no;
|
||||
wt_elem->N_scheduled++;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
} ITERATE_GLTHREAD_END(slot_list, curr)
|
||||
process_wt_reschedule_slotlist(wt);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_wt_elem_reschedule(wheel_timer_t *wt,
|
||||
wheel_timer_elem_t *wt_elem,
|
||||
int new_time_interval,
|
||||
wt_opcode_t opcode){
|
||||
|
||||
if(wt_elem->opcode == WTELEM_DELETE &&
|
||||
(opcode == WTELEM_CREATE ||
|
||||
opcode == WTELEM_RESCHED)){
|
||||
/* This is a Valid Scenario. A Race condition may arise When WT itself
|
||||
* invoked a timer expiry callback for a wt_elem, and at the same time
|
||||
* hello packet also arrived to refresh the same wt_elem.*/
|
||||
//assert(0);
|
||||
}
|
||||
switch(opcode){
|
||||
case WTELEM_CREATE:
|
||||
case WTELEM_RESCHED:
|
||||
case WTELEM_DELETE:
|
||||
|
||||
wt_elem->new_time_interval = new_time_interval;
|
||||
WT_LOCK_SLOT_LIST(WT_GET_RESCHD_SLOTLIST(wt));
|
||||
wt_elem->opcode = opcode;
|
||||
remove_glthread(&wt_elem->reschedule_glue);
|
||||
glthread_add_next(WT_GET_RESCHD_SLOTLIST_HEAD(wt),
|
||||
&wt_elem->reschedule_glue);
|
||||
WT_UNLOCK_SLOT_LIST(WT_GET_RESCHD_SLOTLIST(wt));
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
wheel_timer_elem_t *
|
||||
register_app_event(wheel_timer_t *wt,
|
||||
app_call_back call_back,
|
||||
void *arg,
|
||||
int arg_size,
|
||||
int time_interval,
|
||||
char is_recursive){
|
||||
|
||||
if(!wt || !call_back) return NULL;
|
||||
wheel_timer_elem_t *wt_elem = calloc(1, sizeof(wheel_timer_elem_t));
|
||||
wt_elem->app_callback = call_back;
|
||||
if(arg && arg_size){
|
||||
wt_elem->arg = calloc(1, arg_size);
|
||||
memcpy(wt_elem->arg, arg, arg_size);
|
||||
wt_elem->arg_size = arg_size;
|
||||
}
|
||||
wt_elem->is_recurrence = is_recursive;
|
||||
init_glthread(&wt_elem->glue);
|
||||
init_glthread(&wt_elem->reschedule_glue);
|
||||
wt_elem->N_scheduled = 0;
|
||||
_wt_elem_reschedule(wt, wt_elem, time_interval, WTELEM_CREATE);
|
||||
return wt_elem;
|
||||
}
|
||||
|
||||
void
|
||||
de_register_app_event(wheel_timer_t *wt, wheel_timer_elem_t *wt_elem){
|
||||
|
||||
_wt_elem_reschedule(wt, wt_elem, 0, WTELEM_DELETE);
|
||||
}
|
||||
|
||||
void
|
||||
wt_elem_reschedule(wheel_timer_t *wt,
|
||||
wheel_timer_elem_t *wt_elem,
|
||||
int new_time_interval){
|
||||
|
||||
_wt_elem_reschedule(wt, wt_elem, new_time_interval, WTELEM_RESCHED);
|
||||
}
|
||||
|
||||
int
|
||||
wt_get_remaining_time(wheel_timer_t *wt,
|
||||
wheel_timer_elem_t *wt_elem){
|
||||
|
||||
if(wt_elem->opcode == WTELEM_CREATE ||
|
||||
wt_elem->opcode == WTELEM_RESCHED){
|
||||
/* Means : the wt_elem has not been assigned a slot in WT,
|
||||
* just return the time interval for which it has been scheduled
|
||||
* in this case*/
|
||||
return wt_elem->new_time_interval;
|
||||
}
|
||||
int wt_elem_absolute_slot = (wt_elem->execute_cycle_no * wt->wheel_size) +
|
||||
wt_elem->slot_no;
|
||||
int diff = wt_elem_absolute_slot - GET_WT_CURRENT_ABS_SLOT_NO(wt);
|
||||
return (diff * wt->clock_tic_interval);
|
||||
}
|
||||
|
||||
void
|
||||
free_wheel_timer_element(wheel_timer_elem_t *wt_elem){
|
||||
|
||||
wt_elem->slotlist_head = NULL;
|
||||
free(wt_elem->arg);
|
||||
free(wt_elem);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_wheel_timer(wheel_timer_t *wt){
|
||||
|
||||
int i = 0, j = 0;
|
||||
glthread_t *curr;
|
||||
glthread_t *slot_list_head = NULL;
|
||||
wheel_timer_elem_t *wt_elem = NULL;
|
||||
|
||||
printf("Printing Wheel Timer DS\n");
|
||||
printf("wt->current_clock_tic = %d\n", wt->current_clock_tic);
|
||||
printf("wt->clock_tic_interval = %d\n", wt->clock_tic_interval);
|
||||
printf("wt abs slot no = %d\n", GET_WT_CURRENT_ABS_SLOT_NO(wt));
|
||||
printf("wt->wheel_size = %d\n", wt->wheel_size);
|
||||
printf("wt->current_cycle_no = %d\n", wt->current_cycle_no);
|
||||
printf("wt->wheel_thread = %p\n", &wt->wheel_thread);
|
||||
printf("WT uptime = %s\n", hrs_min_sec_format(WT_UPTIME(wt)));
|
||||
printf("wt->no_of_wt_elem = %u\n", wt->no_of_wt_elem);
|
||||
printf("printing slots : \n");
|
||||
|
||||
for(; i < wt->wheel_size; i++){
|
||||
slot_list_head = WT_SLOTLIST_HEAD(wt, i);
|
||||
ITERATE_GLTHREAD_BEGIN(slot_list_head, curr){
|
||||
wt_elem = glthread_to_wt_elem(curr);
|
||||
printf(" wt_elem->opcode = %d\n", wt_elem->opcode);
|
||||
printf(" wt_elem = %p\n", wt_elem);
|
||||
printf(" wt_elem->time_interval = %d\n", wt_elem->time_interval);
|
||||
printf(" wt_elem->execute_cycle_no = %d\n", wt_elem->execute_cycle_no);
|
||||
printf(" wt_elem->slot_no = %d\n", wt_elem->slot_no);
|
||||
printf(" wt_elem abs slot no = %d\n",
|
||||
(wt_elem->execute_cycle_no * wt->wheel_size) + wt_elem->slot_no);
|
||||
printf(" wt_elem->app_callback = %p\n", wt_elem->app_callback);
|
||||
printf(" wt_elem->arg = %p\n", wt_elem->arg);
|
||||
printf(" wt_elem->is_recurrence = %d\n", wt_elem->is_recurrence);
|
||||
printf(" wt_elem->N_scheduled = %u\n", wt_elem->N_scheduled);
|
||||
printf(" Remaining Time to Fire = %d\n",
|
||||
wt_get_remaining_time(wt, wt_elem));
|
||||
printf("\n");
|
||||
} ITERATE_GLTHREAD_END(slot_list_head , curr)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
start_wheel_timer(wheel_timer_t *wt){
|
||||
|
||||
if (pthread_create(&wt->wheel_thread, NULL, wheel_fn, (void*)wt))
|
||||
{
|
||||
printf("Wheel Timer Thread initialization failed, exiting ... \n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
reset_wheel_timer(wheel_timer_t *wt){
|
||||
wt->current_clock_tic = 0;
|
||||
wt->current_cycle_no = 0;
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
hrs_min_sec_format(unsigned int seconds){
|
||||
|
||||
static char time_f[16];
|
||||
unsigned int hrs = 0,
|
||||
min =0, sec = 0;
|
||||
|
||||
if(seconds > 3600){
|
||||
min = seconds/60;
|
||||
sec = seconds%60;
|
||||
hrs = min/60;
|
||||
min = min%60;
|
||||
}
|
||||
else{
|
||||
min = seconds/60;
|
||||
sec = seconds%60;
|
||||
}
|
||||
memset(time_f, 0, sizeof(time_f));
|
||||
sprintf(time_f, "%u::%u::%u", hrs, min, sec);
|
||||
return time_f;
|
||||
}
|
||||
|
||||
143
WheelTimer/libtimer/WheelTimer/WheelTimer.h
Normal file
143
WheelTimer/libtimer/WheelTimer/WheelTimer.h
Normal file
@@ -0,0 +1,143 @@
|
||||
#ifndef __WHEEL_TIMER__
|
||||
#define __WHEEL_TIMER__
|
||||
|
||||
#include <pthread.h>
|
||||
#include "gluethread/glthread.h"
|
||||
|
||||
typedef struct _wheel_timer_elem_t wheel_timer_elem_t;
|
||||
typedef void (*app_call_back)(void *arg, int sizeof_arg);
|
||||
|
||||
typedef struct slotlist_{
|
||||
glthread_t slots;
|
||||
pthread_mutex_t slot_mutex;
|
||||
}slotlist_t;
|
||||
|
||||
typedef enum{
|
||||
|
||||
WTELEM_CREATE,
|
||||
WTELEM_RESCHED,
|
||||
WTELEM_DELETE,
|
||||
WTELEM_SCHEDULED,
|
||||
WTELEM_UNKNOWN
|
||||
} wt_opcode_t;
|
||||
|
||||
struct _wheel_timer_elem_t{
|
||||
|
||||
wt_opcode_t opcode;
|
||||
int time_interval;
|
||||
int new_time_interval;
|
||||
int execute_cycle_no;
|
||||
int slot_no;
|
||||
app_call_back app_callback;
|
||||
void *arg;
|
||||
int arg_size;
|
||||
char is_recurrence;
|
||||
glthread_t glue;
|
||||
slotlist_t *slotlist_head;
|
||||
glthread_t reschedule_glue;
|
||||
unsigned int N_scheduled;
|
||||
};
|
||||
GLTHREAD_TO_STRUCT(glthread_to_wt_elem, wheel_timer_elem_t, glue);
|
||||
GLTHREAD_TO_STRUCT(glthread_reschedule_glue_to_wt_elem, wheel_timer_elem_t, reschedule_glue);
|
||||
|
||||
typedef struct _wheel_timer_t {
|
||||
int current_clock_tic;
|
||||
int clock_tic_interval;
|
||||
int wheel_size;
|
||||
int current_cycle_no;
|
||||
pthread_t wheel_thread;
|
||||
slotlist_t reschd_list;
|
||||
unsigned int no_of_wt_elem;
|
||||
slotlist_t slotlist[0];
|
||||
} wheel_timer_t;
|
||||
|
||||
#define WT_UPTIME(wt_ptr) \
|
||||
(GET_WT_CURRENT_ABS_SLOT_NO(wt_ptr) * wt_ptr->clock_tic_interval)
|
||||
|
||||
#define WT_SLOTLIST(wt_ptr, index) \
|
||||
(&(wt_ptr->slotlist[index]))
|
||||
|
||||
#define WT_SLOTLIST_HEAD(wt_ptr, index) \
|
||||
(&(wt_ptr->slotlist[index].slots))
|
||||
|
||||
#define WT_SLOTLIST_MUTEX(wt_ptr, index) \
|
||||
(&(wt_ptr->slotlist[index].slot_mutex))
|
||||
|
||||
#define GET_WT_ELEM_SLOT_LIST(wt_elem_ptr) \
|
||||
(wt_elem_ptr->slotlist_head)
|
||||
|
||||
#define WT_LOCK_SLOT_LIST(slotlist_ptr) \
|
||||
pthread_mutex_lock(&(slotlist_ptr->slot_mutex))
|
||||
|
||||
#define WT_UNLOCK_SLOT_LIST(slotlist_ptr) \
|
||||
pthread_mutex_unlock(&(slotlist_ptr->slot_mutex))
|
||||
|
||||
#define WT_LOCK_WTELEM_SLOT_LIST(wt_elem_ptr) \
|
||||
{ \
|
||||
slotlist_t *_slotlist = GET_WT_ELEM_SLOT_LIST(wt_elem_ptr); \
|
||||
if(_slotlist) \
|
||||
WT_LOCK_SLOT_LIST(_slotlist); \
|
||||
}
|
||||
|
||||
#define WT_UNLOCK_WTELEM_SLOT_LIST(wt_elem_ptr) \
|
||||
{ \
|
||||
slotlist_t *_slotlist = GET_WT_ELEM_SLOT_LIST(wt_elem_ptr); \
|
||||
if(_slotlist) \
|
||||
WT_UNLOCK_SLOT_LIST(_slotlist); \
|
||||
}
|
||||
|
||||
#define WT_IS_SLOTLIST_EMPTY(slotlist_ptr) \
|
||||
IS_GLTHREAD_LIST_EMPTY(&(slotlist_ptr->slots))
|
||||
|
||||
#define WT_GET_RESCHD_SLOTLIST(wt_ptr) \
|
||||
(&(wt_ptr->reschd_list))
|
||||
|
||||
#define WT_GET_RESCHD_SLOTLIST_HEAD(wt_ptr) \
|
||||
(&((WT_GET_RESCHD_SLOTLIST(wt_ptr))->slots))
|
||||
|
||||
wheel_timer_t*
|
||||
init_wheel_timer(int wheel_size, int clock_tic_interval);
|
||||
|
||||
|
||||
int
|
||||
wt_get_remaining_time(wheel_timer_t *wt,
|
||||
wheel_timer_elem_t *wt_elem);
|
||||
|
||||
/*Gives the absolute slot no since the time WT has started*/
|
||||
#define GET_WT_CURRENT_ABS_SLOT_NO(wt) ((wt->current_cycle_no * wt->wheel_size) + wt->current_clock_tic)
|
||||
|
||||
wheel_timer_elem_t *
|
||||
register_app_event(wheel_timer_t *wt,
|
||||
app_call_back call_back,
|
||||
void *arg,
|
||||
int arg_size,
|
||||
int time_interval,
|
||||
char is_recursive);
|
||||
|
||||
void
|
||||
de_register_app_event(wheel_timer_t *wt, wheel_timer_elem_t *wt_elem);
|
||||
|
||||
void
|
||||
wt_elem_reschedule(wheel_timer_t *wt,
|
||||
wheel_timer_elem_t *wt_elem,
|
||||
int new_time_interval);
|
||||
|
||||
void
|
||||
free_wheel_timer_element(wheel_timer_elem_t *wt_elem);
|
||||
|
||||
void
|
||||
print_wheel_timer(wheel_timer_t *wt);
|
||||
|
||||
void
|
||||
start_wheel_timer(wheel_timer_t *wt);
|
||||
|
||||
void
|
||||
cancel_wheel_timer(wheel_timer_t *wt);
|
||||
|
||||
void
|
||||
reset_wheel_timer(wheel_timer_t *wt);
|
||||
|
||||
char*
|
||||
hrs_min_sec_format(unsigned int seconds);
|
||||
|
||||
#endif
|
||||
200
WheelTimer/libtimer/gluethread/glthread.c
Normal file
200
WheelTimer/libtimer/gluethread/glthread.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: glthread.c
|
||||
*
|
||||
* Description: Implementation of glthread Library
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: Monday 12 March 2018 02:13:36 IST
|
||||
* Revision: 1.0
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Er. Abhishek Sagar, Networking Developer (AS), sachinites@gmail.com
|
||||
* Company: Brocade Communications(Jul 2012- Mar 2016), Current : Juniper Networks(Apr 2017 - Present)
|
||||
*
|
||||
* This file is part of the SPFComputation distribution (https://github.com/sachinites).
|
||||
* Copyright (c) 2017 Abhishek Sagar.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
|
||||
#include "glthread.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void
|
||||
init_glthread(glthread_t *glthread){
|
||||
|
||||
glthread->left = NULL;
|
||||
glthread->right = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
glthread_add_next(glthread_t *curr_glthread, glthread_t *new_glthread){
|
||||
|
||||
if(!curr_glthread->right){
|
||||
curr_glthread->right = new_glthread;
|
||||
new_glthread->left = curr_glthread;
|
||||
return;
|
||||
}
|
||||
|
||||
glthread_t *temp = curr_glthread->right;
|
||||
curr_glthread->right = new_glthread;
|
||||
new_glthread->left = curr_glthread;
|
||||
new_glthread->right = temp;
|
||||
temp->left = new_glthread;
|
||||
}
|
||||
|
||||
void
|
||||
glthread_add_before(glthread_t *curr_glthread, glthread_t *new_glthread){
|
||||
|
||||
if(!curr_glthread->left){
|
||||
new_glthread->left = NULL;
|
||||
new_glthread->right = curr_glthread;
|
||||
curr_glthread->left = new_glthread;
|
||||
return;
|
||||
}
|
||||
|
||||
glthread_t *temp = curr_glthread->left;
|
||||
temp->right = new_glthread;
|
||||
new_glthread->left = temp;
|
||||
new_glthread->right = curr_glthread;
|
||||
curr_glthread->left = new_glthread;
|
||||
}
|
||||
|
||||
void
|
||||
remove_glthread(glthread_t *curr_glthread){
|
||||
|
||||
if(!curr_glthread->left){
|
||||
if(curr_glthread->right){
|
||||
curr_glthread->right->left = NULL;
|
||||
curr_glthread->right = 0;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(!curr_glthread->right){
|
||||
curr_glthread->left->right = NULL;
|
||||
curr_glthread->left = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
curr_glthread->left->right = curr_glthread->right;
|
||||
curr_glthread->right->left = curr_glthread->left;
|
||||
curr_glthread->left = 0;
|
||||
curr_glthread->right = 0;
|
||||
}
|
||||
|
||||
void
|
||||
delete_glthread_list(glthread_t *base_glthread){
|
||||
|
||||
glthread_t *glthreadptr = NULL;
|
||||
|
||||
ITERATE_GLTHREAD_BEGIN(base_glthread, glthreadptr){
|
||||
remove_glthread(glthreadptr);
|
||||
} ITERATE_GLTHREAD_END(base_glthread, glthreadptr);
|
||||
}
|
||||
|
||||
void
|
||||
glthread_add_last(glthread_t *base_glthread, glthread_t *new_glthread){
|
||||
|
||||
glthread_t *glthreadptr = NULL,
|
||||
*prevglthreadptr = NULL;
|
||||
|
||||
ITERATE_GLTHREAD_BEGIN(base_glthread, glthreadptr){
|
||||
prevglthreadptr = glthreadptr;
|
||||
} ITERATE_GLTHREAD_END(base_glthread, glthreadptr);
|
||||
|
||||
if(prevglthreadptr)
|
||||
glthread_add_next(prevglthreadptr, new_glthread);
|
||||
else
|
||||
glthread_add_next(base_glthread, new_glthread);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
get_glthread_list_count(glthread_t *base_glthread){
|
||||
|
||||
unsigned int count = 0;
|
||||
glthread_t *glthreadptr = NULL;
|
||||
|
||||
ITERATE_GLTHREAD_BEGIN(base_glthread, glthreadptr){
|
||||
count++;
|
||||
} ITERATE_GLTHREAD_END(base_glthread, glthreadptr);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
glthread_priority_insert(glthread_t *base_glthread,
|
||||
glthread_t *glthread,
|
||||
int (*comp_fn)(void *, void *),
|
||||
int offset){
|
||||
|
||||
|
||||
glthread_t *curr = NULL,
|
||||
*prev = NULL;
|
||||
|
||||
init_glthread(glthread);
|
||||
|
||||
if(IS_GLTHREAD_LIST_EMPTY(base_glthread)){
|
||||
glthread_add_next(base_glthread, glthread);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only one node*/
|
||||
if(base_glthread->right && !base_glthread->right->right){
|
||||
if(comp_fn(GLTHREAD_GET_USER_DATA_FROM_OFFSET(base_glthread->right, offset),
|
||||
GLTHREAD_GET_USER_DATA_FROM_OFFSET(glthread, offset)) == -1){
|
||||
glthread_add_next(base_glthread->right, glthread);
|
||||
}
|
||||
else{
|
||||
glthread_add_next(base_glthread, glthread);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(comp_fn(GLTHREAD_GET_USER_DATA_FROM_OFFSET(glthread, offset),
|
||||
GLTHREAD_GET_USER_DATA_FROM_OFFSET(base_glthread->right, offset)) == -1){
|
||||
glthread_add_next(base_glthread, glthread);
|
||||
return;
|
||||
}
|
||||
|
||||
ITERATE_GLTHREAD_BEGIN(base_glthread, curr){
|
||||
|
||||
if(comp_fn(GLTHREAD_GET_USER_DATA_FROM_OFFSET(glthread, offset),
|
||||
GLTHREAD_GET_USER_DATA_FROM_OFFSET(curr, offset)) != -1){
|
||||
prev = curr;
|
||||
continue;
|
||||
}
|
||||
|
||||
glthread_add_next(curr, glthread);
|
||||
return;
|
||||
|
||||
}ITERATE_GLTHREAD_END(base_glthread, curr);
|
||||
|
||||
/*Add in the end*/
|
||||
glthread_add_next(prev, glthread);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void *
|
||||
gl_thread_search(glthread_t *base_glthread,
|
||||
void *(*thread_to_struct_fn)(glthread_t *),
|
||||
void *key,
|
||||
int (*comparison_fn)(void *, void *)){
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
104
WheelTimer/libtimer/gluethread/glthread.h
Normal file
104
WheelTimer/libtimer/gluethread/glthread.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: glthread.h
|
||||
*
|
||||
* Description: This file defines the Data structure and APIs for Glue thread
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: Monday 12 March 2018 02:01:51 IST
|
||||
* Revision: 1.0
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Er. Abhishek Sagar, Networking Developer (AS), sachinites@gmail.com
|
||||
* Company: Brocade Communications(Jul 2012- Mar 2016), Current : Juniper Networks(Apr 2017 - Present)
|
||||
*
|
||||
* This file is part of the SPFComputation distribution (https://github.com/sachinites).
|
||||
* Copyright (c) 2017 Abhishek Sagar.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __GLUETHREAD__
|
||||
#define __GLUETHREAD__
|
||||
|
||||
typedef struct _glthread{
|
||||
|
||||
struct _glthread *left;
|
||||
struct _glthread *right;
|
||||
} glthread_t;
|
||||
|
||||
void
|
||||
glthread_add_next(glthread_t *base_glthread, glthread_t *new_glthread);
|
||||
|
||||
void
|
||||
glthread_add_before(glthread_t *base_glthread, glthread_t *new_glthread);
|
||||
|
||||
void
|
||||
remove_glthread(glthread_t *glthread);
|
||||
|
||||
void
|
||||
init_glthread(glthread_t *glthread);
|
||||
|
||||
void
|
||||
glthread_add_last(glthread_t *base_glthread, glthread_t *new_glthread);
|
||||
|
||||
#define IS_GLTHREAD_LIST_EMPTY(glthreadptr) \
|
||||
((glthreadptr)->right == 0 && (glthreadptr)->left == 0)
|
||||
|
||||
#define GLTHREAD_TO_STRUCT(fn_name, structure_name, field_name) \
|
||||
static inline structure_name * fn_name(glthread_t *glthreadptr){ \
|
||||
return (structure_name *)((char *)(glthreadptr) - (char *)&(((structure_name *)0)->field_name)); \
|
||||
}
|
||||
|
||||
/* delete safe loop*/
|
||||
/*Normal continue and break can be used with this loop macro*/
|
||||
|
||||
#define BASE(glthreadptr) ((glthreadptr)->right)
|
||||
|
||||
#define ITERATE_GLTHREAD_BEGIN(glthreadptrstart, glthreadptr) \
|
||||
{ \
|
||||
glthread_t *_glthread_ptr = NULL; \
|
||||
glthreadptr = BASE(glthreadptrstart); \
|
||||
for(; glthreadptr!= NULL; glthreadptr = _glthread_ptr){ \
|
||||
_glthread_ptr = (glthreadptr)->right;
|
||||
|
||||
#define ITERATE_GLTHREAD_END(glthreadptrstart, glthreadptr) \
|
||||
}}
|
||||
|
||||
#define GLTHREAD_GET_USER_DATA_FROM_OFFSET(glthreadptr, offset) \
|
||||
(void *)((char *)(glthreadptr) - offset)
|
||||
|
||||
void
|
||||
delete_glthread_list(glthread_t *base_glthread);
|
||||
|
||||
unsigned int
|
||||
get_glthread_list_count(glthread_t *base_glthread);
|
||||
|
||||
void
|
||||
glthread_priority_insert(glthread_t *base_glthread,
|
||||
glthread_t *glthread,
|
||||
int (*comp_fn)(void *, void *),
|
||||
int offset);
|
||||
|
||||
|
||||
#if 0
|
||||
void *
|
||||
gl_thread_search(glthread_t *base_glthread,
|
||||
void *(*thread_to_struct_fn)(glthread_t *),
|
||||
void *key,
|
||||
int (*comparison_fn)(void *, void *));
|
||||
|
||||
#endif
|
||||
#endif /* __GLUETHREAD__ */
|
||||
90
WheelTimer/libtimer/gluethread/test.c
Normal file
90
WheelTimer/libtimer/gluethread/test.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: test.c
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: Monday 12 March 2018 02:15:28 IST
|
||||
* Revision: 1.0
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Er. Abhishek Sagar, Networking Developer (AS), sachinites@gmail.com
|
||||
* Company: Brocade Communications(Jul 2012- Mar 2016), Current : Juniper Networks(Apr 2017 - Present)
|
||||
*
|
||||
* This file is part of the XXX distribution (https://github.com/sachinites).
|
||||
* Copyright (c) 2017 Abhishek Sagar.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#include "glthread.h"
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct _person{
|
||||
|
||||
int age;
|
||||
int weight;
|
||||
glthread_t glthread;
|
||||
} person_t ;
|
||||
|
||||
int
|
||||
senior_citizen(person_t *p1, person_t *p2){
|
||||
|
||||
if(p1->age == p2->age) return 0;
|
||||
if(p1->age < p2->age) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define offset(struct_name, fld_name) \
|
||||
(unsigned int)&(((struct_name *)0)->fld_name)
|
||||
|
||||
GLTHREAD_TO_STRUCT(thread_to_person, person_t, glthread, glthreadptr);
|
||||
|
||||
int main(int argc, char **argv){
|
||||
|
||||
person_t person[5];
|
||||
memset(person, 0, sizeof(person_t) * 5);
|
||||
person[0].age = 1;
|
||||
person[0].weight = 2;
|
||||
person[1].age = 3;
|
||||
person[1].weight = 4;
|
||||
person[2].age = 5;
|
||||
person[2].weight = 6;
|
||||
person[3].age = 7;
|
||||
person[3].weight = 8;
|
||||
person[4].age = 9;
|
||||
person[4].weight = 10;
|
||||
|
||||
glthread_t base_glthread;
|
||||
init_glthread(&base_glthread);
|
||||
|
||||
glthread_priority_insert(&base_glthread, &person[4].glthread, senior_citizen, offset(person_t, glthread));
|
||||
glthread_priority_insert(&base_glthread, &person[3].glthread, senior_citizen, offset(person_t, glthread));
|
||||
glthread_priority_insert(&base_glthread, &person[2].glthread, senior_citizen, offset(person_t, glthread));
|
||||
glthread_priority_insert(&base_glthread, &person[1].glthread, senior_citizen, offset(person_t, glthread));
|
||||
glthread_priority_insert(&base_glthread, &person[0].glthread, senior_citizen, offset(person_t, glthread));
|
||||
|
||||
glthread_t *curr = NULL;
|
||||
ITERATE_GLTHREAD_BEGIN(&base_glthread, curr){
|
||||
|
||||
person_t *p = thread_to_person(curr);
|
||||
printf("Age = %d\n", p->age);
|
||||
} ITERATE_GLTHREAD_END(&base_glthread, curr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -189,7 +189,6 @@ timer_demo(){
|
||||
printf("Timer Start failed, errno = %d\n", errno);
|
||||
exit(0);
|
||||
}
|
||||
pause();
|
||||
}
|
||||
|
||||
/* Returns NULL in timer creation fails, else
|
||||
|
||||
@@ -134,7 +134,6 @@ void
|
||||
resurrect_timer(Timer_t *timer){
|
||||
|
||||
int rc;
|
||||
|
||||
rc = timer_settime(*(timer->posix_timer), 0, &timer->ts, NULL);
|
||||
assert(rc >= 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user