Updated base WheelTimer (WheelTimer.c, WheelTimer.h) files to point to

latest WheelTimer code.
This commit is contained in:
Abhishek Sagar
2020-10-28 13:06:25 -07:00
parent 0d5a0dff84
commit 22b740a60d
7 changed files with 723 additions and 145 deletions

View File

@@ -4,141 +4,253 @@
#include <memory.h> #include <memory.h>
#include <unistd.h> #include <unistd.h>
#include <time.h> #include <time.h>
#include "LinkedListApi.h" #include <assert.h>
#define TH_JOINABLE 1 #define TH_JOINABLE 1
#define TH_DETACHED 0 #define TH_DETACHED 0
extern blocked_pool_t gl_blocked_th_pool;
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* wheel_timer_t*
init_wheel_timer(int wheel_size, int clock_tic_interval){ init_wheel_timer(int wheel_size, int clock_tic_interval){
wheel_timer_t *wt = calloc(1, sizeof(wheel_timer_t) + wheel_timer_t *wt = calloc(1, sizeof(wheel_timer_t) +
wheel_size*sizeof(ll_t *)); (wheel_size * sizeof(slotlist_t)));
wt->clock_tic_interval = clock_tic_interval; wt->clock_tic_interval = clock_tic_interval;
wt->wheel_size = wheel_size; wt->wheel_size = wheel_size;
pthread_mutex_init(&wt->wheel_timer_mutex, NULL); memset(&(wt->wheel_thread), 0, sizeof(wheel_timer_t));
wt->wheel_thread = calloc(1, sizeof(_pthread_t));
pthread_init(wt->wheel_thread, 0, TH_DETACHED);
int i = 0; int i = 0;
for(; i < wheel_size; i++) for(; i < wheel_size; i++){
wt->slots[i] = init_singly_ll(); init_glthread(WT_SLOTLIST_HEAD(wt, i));
pthread_mutex_init(WT_SLOTLIST_MUTEX(wt, i), NULL);
}
wt->no_of_wt_elem = 0;
return wt; return wt;
} }
void static void
de_register_app_event(wheel_timer_t *wt, wheel_timer_elem_t *wt_elem){ process_wt_reschedule_slotlist(wheel_timer_t *wt){
if(!wt_elem) return;
pause_wheel_timer(wt); glthread_t *curr;
wt_elem->is_alive = 0; wheel_timer_elem_t *wt_elem;
resume_wheel_timer(wt);
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* static void *
wheel_fn(void *arg){ wheel_fn(void *arg){
wheel_timer_t *wt = (wheel_timer_t *)arg; wheel_timer_t *wt = (wheel_timer_t *)arg;
wheel_timer_elem_t *wt_elem = NULL; wheel_timer_elem_t *wt_elem = NULL;
int absolute_slot_no = 0, i =0; int absolute_slot_no = 0, i =0;
ll_t *slot_list = NULL; slotlist_t *slot_list = NULL;
singly_ll_node_t *head = NULL, *next_node = NULL; glthread_t *curr;
while(1){ while(1){
wt->current_clock_tic++;
wt->current_clock_tic = (wt->current_clock_tic % wt->wheel_size); wt->current_clock_tic++;
if(wt->current_clock_tic == 0) if(wt->current_clock_tic == wt->wheel_size){
wt->current_cycle_no++; wt->current_clock_tic = 0;
wt->current_cycle_no++;
}
sleep(wt->clock_tic_interval); sleep(wt->clock_tic_interval);
tentative_wait(wt->wheel_thread, &wt->wheel_timer_mutex);
slot_list = wt->slots[wt->current_clock_tic]; slot_list = WT_SLOTLIST(wt, wt->current_clock_tic);
head = GET_HEAD_SINGLY_LL(slot_list);
int node_count = GET_NODE_COUNT_SINGLY_LL(slot_list);
absolute_slot_no = GET_WT_CURRENT_ABS_SLOT_NO(wt); absolute_slot_no = GET_WT_CURRENT_ABS_SLOT_NO(wt);
printf("Wheel Timer Time = %d : ", absolute_slot_no * wt->clock_tic_interval);
if(!node_count)
printf("\n");
for(i = 0; i < node_count; i++){
next_node = GET_NEXT_NODE_SINGLY_LL(head);
wt_elem = (wheel_timer_elem_t *)head->data;
if(wt_elem->is_alive == 0){ ITERATE_GLTHREAD_BEGIN(&slot_list->slots, curr){
singly_ll_remove_node(slot_list, head);
free_wheel_timer_element(wt_elem);
free(head);
head = next_node;
continue;
}
wt_elem = glthread_to_wt_elem(curr);
/*Check if R == r*/
if(wt->current_cycle_no == wt_elem->execute_cycle_no){ 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); 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){ if(wt_elem->is_recurrence){
/*relocate*/
int next_abs_slot_no = absolute_slot_no + (wt_elem->time_interval/wt->clock_tic_interval); /*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_cycle_no = next_abs_slot_no / wt->wheel_size;
int next_slot_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->execute_cycle_no = next_cycle_no;
if(next_slot_no == wt->current_clock_tic){ remove_glthread(&wt_elem->glue);
head = next_node; glthread_priority_insert(WT_SLOTLIST_HEAD(wt, next_slot_no), &wt_elem->glue,
continue; insert_wt_elem_in_slot,
} (unsigned long)&((wheel_timer_elem_t *)0)->glue);
singly_ll_remove_node(slot_list, head); wt_elem->slotlist_head = WT_SLOTLIST(wt, next_slot_no);
singly_ll_add_node(wt->slots[next_slot_no], head); wt_elem->slot_no = next_slot_no;
} wt_elem->N_scheduled++;
else{
free_wheel_timer_element((wheel_timer_elem_t *)head->data);
singly_ll_delete_node(slot_list, head);
} }
} }
head = next_node; else
} break;
} ITERATE_GLTHREAD_END(slot_list, curr)
process_wt_reschedule_slotlist(wt);
} }
return NULL; 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 * wheel_timer_elem_t *
register_app_event(wheel_timer_t *wt, register_app_event(wheel_timer_t *wt,
app_call_back call_back, app_call_back call_back,
void *arg, void *arg,
int arg_size, int arg_size,
int time_interval, int time_interval,
char is_recursive){ char is_recursive){
if(!wt || !call_back) return NULL; if(!wt || !call_back) return NULL;
wheel_timer_elem_t *wt_elem = calloc(1, sizeof(wheel_timer_elem_t)); wheel_timer_elem_t *wt_elem = calloc(1, sizeof(wheel_timer_elem_t));
wt_elem->time_interval = time_interval;
wt_elem->app_callback = call_back; wt_elem->app_callback = call_back;
wt_elem->arg = calloc(1, arg_size); if(arg && arg_size){
memcpy(wt_elem->arg, arg, arg_size); wt_elem->arg = calloc(1, arg_size);
wt_elem->arg_size = arg_size; memcpy(wt_elem->arg, arg, arg_size);
wt_elem->arg_size = arg_size;
}
wt_elem->is_recurrence = is_recursive; 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;
}
/*Stop the Wheel timer Thread here*/ void
pause_wheel_timer(wt); de_register_app_event(wheel_timer_t *wt, wheel_timer_elem_t *wt_elem){
int wt_absolute_slot = GET_WT_CURRENT_ABS_SLOT_NO(wt); _wt_elem_reschedule(wt, wt_elem, 0, WTELEM_DELETE);
int registration_next_abs_slot = wt_absolute_slot + (wt_elem->time_interval/wt->clock_tic_interval); }
int cycle_no = registration_next_abs_slot / wt->wheel_size;
int slot_no = registration_next_abs_slot % wt->wheel_size;
wt_elem->execute_cycle_no = cycle_no;
wt_elem->is_alive = 1;
singly_ll_add_node_by_val(wt->slots[slot_no], wt_elem);
//printf("Wheel Timer snapshot on New Registration\n");
//print_wheel_timer(wt);
resume_wheel_timer(wt); void
return wt_elem; 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 void
free_wheel_timer_element(wheel_timer_elem_t *wt_elem){ free_wheel_timer_element(wheel_timer_elem_t *wt_elem){
wt_elem->slotlist_head = NULL;
free(wt_elem->arg); free(wt_elem->arg);
free(wt_elem); free(wt_elem);
} }
@@ -146,46 +258,49 @@ free_wheel_timer_element(wheel_timer_elem_t *wt_elem){
void void
print_wheel_timer(wheel_timer_t *wt){ print_wheel_timer(wheel_timer_t *wt){
int i = 0, j = 0;
ll_t* slot_list = NULL; int i = 0, j = 0;
glthread_t *curr;
glthread_t *slot_list_head = NULL;
wheel_timer_elem_t *wt_elem = NULL; wheel_timer_elem_t *wt_elem = NULL;
singly_ll_node_t *head = NULL;
printf("Printing Wheel Timer DS\n"); printf("Printing Wheel Timer DS\n");
printf("wt->current_clock_tic = %d\n", wt->current_clock_tic); printf("wt->current_clock_tic = %d\n", wt->current_clock_tic);
printf("wt->clock_tic_interval = %d\n", wt->clock_tic_interval); 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->wheel_size = %d\n", wt->wheel_size);
printf("wt->current_cycle_no = %d\n", wt->current_cycle_no); printf("wt->current_cycle_no = %d\n", wt->current_cycle_no);
printf("wt->wheel_thread = %p\n", wt->wheel_thread); 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"); printf("printing slots : \n");
for(; i < wt->wheel_size; i++){ for(; i < wt->wheel_size; i++){
slot_list = wt->slots[i]; slot_list_head = WT_SLOTLIST_HEAD(wt, i);
printf(" slot_list[%d] : count : %d\n", i, GET_NODE_COUNT_SINGLY_LL(slot_list)); ITERATE_GLTHREAD_BEGIN(slot_list_head, curr){
head = GET_HEAD_SINGLY_LL(slot_list); wt_elem = glthread_to_wt_elem(curr);
for(j = 0 ; j < GET_NODE_COUNT_SINGLY_LL(slot_list); j++){ printf(" wt_elem->opcode = %d\n", wt_elem->opcode);
wt_elem = (wheel_timer_elem_t *)head->data; printf(" wt_elem = %p\n", wt_elem);
if(!wt_elem){ printf(" wt_elem->time_interval = %d\n", wt_elem->time_interval);
printf(" NULL\n");
head = GET_NEXT_NODE_SINGLY_LL(head);
continue;
}
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->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->app_callback = %p\n", wt_elem->app_callback);
printf(" wt_elem->arg = %p\n", wt_elem->arg); printf(" wt_elem->arg = %p\n", wt_elem->arg);
printf(" wt_elem->is_recurrence = %d\n", wt_elem->is_recurrence); printf(" wt_elem->is_recurrence = %d\n", wt_elem->is_recurrence);
head = GET_NEXT_NODE_SINGLY_LL(head); 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 void
start_wheel_timer(wheel_timer_t *wt){ start_wheel_timer(wheel_timer_t *wt){
_pthread_t *thread = wt->wheel_thread; if (pthread_create(&wt->wheel_thread, NULL, wheel_fn, (void*)wt))
if (pthread_create(&thread->pthread_handle, &thread->attr, wheel_fn, (void*)wt))
{ {
printf("Wheel Timer Thread initialization failed, exiting ... \n"); printf("Wheel Timer Thread initialization failed, exiting ... \n");
exit(0); exit(0);
@@ -198,21 +313,26 @@ reset_wheel_timer(wheel_timer_t *wt){
wt->current_cycle_no = 0; wt->current_cycle_no = 0;
} }
void
pause_wheel_timer(wheel_timer_t *wt){ char*
send_wait_order(wt->wheel_thread); 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;
} }
void
resume_wheel_timer(wheel_timer_t *wt){
signal_t(wt->wheel_thread);
}
void
wt_elem_reschedule(wheel_timer_elem_t *wt_elem, int new_time_interval){
if(!wt_elem) return;
if(new_time_interval <= 0)
return;
wt_elem->time_interval = new_time_interval;
}

View File

@@ -1,40 +1,110 @@
#ifndef __WHEEL_TIMER__ #ifndef __WHEEL_TIMER__
#define __WHEEL_TIMER__ #define __WHEEL_TIMER__
#include "threadApi.h"
#include <pthread.h>
#include "gluethread/glthread.h"
typedef struct _wheel_timer_elem_t wheel_timer_elem_t; typedef struct _wheel_timer_elem_t wheel_timer_elem_t;
typedef void (*app_call_back)(void *arg, int sizeof_arg); typedef void (*app_call_back)(void *arg, int sizeof_arg);
typedef struct LL ll_t;
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{ struct _wheel_timer_elem_t{
wt_opcode_t opcode;
int time_interval; int time_interval;
int new_time_interval;
int execute_cycle_no; int execute_cycle_no;
int slot_no;
app_call_back app_callback; app_call_back app_callback;
void *arg; void *arg;
int arg_size; int arg_size;
char is_recurrence; char is_recurrence;
/* control param*/ glthread_t glue;
char is_alive; 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 { typedef struct _wheel_timer_t {
int current_clock_tic; int current_clock_tic;
int clock_tic_interval; int clock_tic_interval;
int wheel_size; int wheel_size;
int current_cycle_no; int current_cycle_no;
_pthread_t *wheel_thread; pthread_t wheel_thread;
pthread_mutex_t wheel_timer_mutex; slotlist_t reschd_list;
ll_t *slots[0]; unsigned int no_of_wt_elem;
slotlist_t slotlist[0];
} wheel_timer_t; } 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* wheel_timer_t*
init_wheel_timer(int wheel_size, int clock_tic_interval); init_wheel_timer(int wheel_size, int clock_tic_interval);
#define GET_WT_CURRENT_ABS_SLOT_NO(wt) ((wt->current_cycle_no * wt->wheel_size) + wt->current_clock_tic)
void int
cleanup_wheel_timer(wheel_timer_t *wt); 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 * wheel_timer_elem_t *
register_app_event(wheel_timer_t *wt, register_app_event(wheel_timer_t *wt,
@@ -44,12 +114,13 @@ register_app_event(wheel_timer_t *wt,
int time_interval, int time_interval,
char is_recursive); char is_recursive);
void void
de_register_app_event(wheel_timer_t *wt, wheel_timer_elem_t *wt_elem); de_register_app_event(wheel_timer_t *wt, wheel_timer_elem_t *wt_elem);
void void
wt_elem_reschedule(wheel_timer_elem_t *wt_elem, int new_time_interval); wt_elem_reschedule(wheel_timer_t *wt,
wheel_timer_elem_t *wt_elem,
int new_time_interval);
void void
free_wheel_timer_element(wheel_timer_elem_t *wt_elem); free_wheel_timer_element(wheel_timer_elem_t *wt_elem);
@@ -60,16 +131,13 @@ print_wheel_timer(wheel_timer_t *wt);
void void
start_wheel_timer(wheel_timer_t *wt); start_wheel_timer(wheel_timer_t *wt);
void
pause_wheel_timer(wheel_timer_t *wt);
void void
cancel_wheel_timer(wheel_timer_t *wt); cancel_wheel_timer(wheel_timer_t *wt);
void void
reset_wheel_timer(wheel_timer_t *wt); reset_wheel_timer(wheel_timer_t *wt);
void char*
resume_wheel_timer(wheel_timer_t *wt); hrs_min_sec_format(unsigned int seconds);
#endif #endif

View 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

View 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__ */

View 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;
}

View File

@@ -1,15 +1,12 @@
#include "WheelTimer.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <memory.h> #include <memory.h>
#include "WheelTimer.h"
#define MAX_NUMBER_APP_THREADS 1
#define WHEEL_SIZE 15 #define WHEEL_SIZE 15
#define WHEEL_TIMER_CLOCK_TIC_INTERVAL 1 // sec #define WHEEL_TIMER_CLOCK_TIC_INTERVAL 1 // sec
/*Import Library global Variables*/ wheel_timer_t *wt;
extern blocked_pool_t gl_blocked_th_pool;
void void
generate_general_query(int vlan){ generate_general_query(int vlan){
@@ -77,7 +74,7 @@ main_menu(wheel_timer_t *wt){
int new_time_interval = 0; int new_time_interval = 0;
printf("Enter new time interval : "); printf("Enter new time interval : ");
scanf("%d", &new_time_interval); scanf("%d", &new_time_interval);
wt_elem_reschedule(gq_wt_elem, new_time_interval); wt_elem_reschedule(wt, gq_wt_elem, new_time_interval);
} }
break; break;
case 11: case 11:
@@ -85,7 +82,7 @@ main_menu(wheel_timer_t *wt){
int new_time_interval = 0; int new_time_interval = 0;
printf("Enter new time interval : "); printf("Enter new time interval : ");
scanf("%d", &new_time_interval); scanf("%d", &new_time_interval);
wt_elem_reschedule(pim_hello_wt_elem, new_time_interval); wt_elem_reschedule(wt, pim_hello_wt_elem, new_time_interval);
} }
break; break;
case 12: case 12:
@@ -93,7 +90,7 @@ main_menu(wheel_timer_t *wt){
int new_time_interval = 0; int new_time_interval = 0;
printf("Enter new time interval : "); printf("Enter new time interval : ");
scanf("%d", &new_time_interval); scanf("%d", &new_time_interval);
wt_elem_reschedule(ospf_hello_wt_elem, new_time_interval); wt_elem_reschedule(wt, ospf_hello_wt_elem, new_time_interval);
} }
break; break;
case 6: case 6:
@@ -173,9 +170,7 @@ main_menu(wheel_timer_t *wt){
int int
main(int argc, char **argv){ main(int argc, char **argv){
init_blocked_pool(&gl_blocked_th_pool, MAX_NUMBER_APP_THREADS); wt = init_wheel_timer(WHEEL_SIZE, WHEEL_TIMER_CLOCK_TIC_INTERVAL);
wheel_timer_t *wt =
init_wheel_timer(WHEEL_SIZE, WHEEL_TIMER_CLOCK_TIC_INTERVAL);
start_wheel_timer(wt); start_wheel_timer(wt);
/* WT thread is in DETACHED MODE, so below call is useless*/ /* WT thread is in DETACHED MODE, so below call is useless*/

View File

@@ -2,6 +2,7 @@ This is the simple demostration of WheelTimer in C
you should have gcc compiler installed to compile the project. you should have gcc compiler installed to compile the project.
run 'make' to compile the project use this cmd to create executable :
gcc -g main.c gluethread/glthread.c WheelTimer.c -o exe -lpthread
run ./exe to launch the application run ./exe to launch the application