Wheel Timer Implemented

This commit is contained in:
2024-06-01 22:04:37 +05:30
parent ca9002946f
commit d96bc7582c
9 changed files with 805 additions and 15 deletions

View File

@@ -3,6 +3,7 @@
#include <stdint.h>
#include <timerlib.h>
#include <assert.h>
#include <string.h>
#include "rt.h"
static rt_table_t rt;

View File

@@ -21,6 +21,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/$<CONFIG>")
#Library Name...
set(TIMER_LIB timer)
set(WHEELTIMER_LIB wheeltimer)
#Header file directory...

View File

@@ -1,20 +1,148 @@
#ifndef __WHEEL_TIMER_H
#define __WHEEL_TIMER_H
#ifndef __WHEEL_TIMER__
#define __WHEEL_TIMER__
//To use POSIX TIMER library
#define __USE_POSIX199309 1
#include <pthread.h>
#include <timerlib.h>
#include <glthread.h>
typdedef struct _wheel_timer_t {
typedef struct _wheel_timer_elem_t wheel_timer_elem_t;
typedef void (*app_call_back)(void* arg, int sizeof_arg);
int current_clock_tic; /*Pointer to current slot, pointed by clock tic*/
int clock_tic_interval; /*Time interval of each clock tick*/
int wheel_size; /*No. of slots in wheel timer*/
int current_cycle_no; /*No. of rotation completed by wheel timer clock tic*/
pthread_t wheel_thread; /*Thread where the wheel timer clock run separately*/
/*@@@@@@@@@@@@*/
ll_t* slots[0]; /*Array of linked list, where each index in array represent a slot*/
/*@@@@@@@@@@@@*/
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;
Timer_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

72
include/glthread.h Normal file
View File

@@ -0,0 +1,72 @@
#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

@@ -1,11 +1,17 @@
#timerlib.c src file...
set(TIMER_LIB_SRC "timerlib.c")
set(WHEEL_TIMER_LIB_SRC "WheelTimer.c")
set(GLTHREAD "glthread.c")
#Library
add_library(${TIMER_LIB} STATIC
${TIMER_LIB_SRC}
${WHEEL_TIMER_LIB_SRC})
${TIMER_LIB_SRC})
add_library(${WHEELTIMER_LIB} STATIC
${TIMER_LIB_SRC}
${GLTHREAD}
${WHEEL_TIMER_LIB_SRC})
#Linking dependent library...
@@ -19,12 +25,19 @@ set(POSIX_TIMER_LIB rt)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
#Below snippet is important for POSIX timer library in WSL2...
target_compile_definitions(wheeltimer PRIVATE _POSIX_C_SOURCE=199309L)
target_link_libraries(${TIMER_LIB} PUBLIC
${POSIX_TIMER_LIB}
Threads::Threads)
target_link_libraries(${WHEELTIMER_LIB} PUBLIC
${POSIX_TIMER_LIB}
Threads::Threads)
#Including Header file dir...
target_include_directories(${TIMER_LIB} PUBLIC
${HEADER_DIR})
target_include_directories(${WHEELTIMER_LIB} PUBLIC
${HEADER_DIR})

View File

@@ -0,0 +1,342 @@
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <unistd.h>
#include <time.h>
#include <assert.h>
#include <timerlib.h>
#include <WheelTimer.h>
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;
}
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(Timer_t* timer, 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;
wt->current_clock_tic++;
if (wt->current_clock_tic == wt->wheel_size) {
wt->current_clock_tic = 0;
wt->current_cycle_no++;
}
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);
}
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;
wt->wheel_thread = setup_timer(wheel_fn,
wt->clock_tic_interval * 1000,
wt->clock_tic_interval * 1000,
0,
(void*)wt,
false);
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
_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;
pause_timer(wt->wheel_thread);
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));
resume_timer(wt->wheel_thread);
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) {
start_timer(wt->wheel_thread);
}
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;
}
void
cancel_wheel_timer(wheel_timer_t* wt) {
if (wt->wheel_thread) {
cancel_timer(wt->wheel_thread);
}
}

167
src/glthread.c Normal file
View File

@@ -0,0 +1,167 @@
#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

@@ -1,12 +1,25 @@
set(TIMERLIB_TEST_EXE timerlib_test)
set(WHEELTIMER_TEST_EXE wheeltimer_test)
set(TIMERLIB_TEST_SRC "timerlib_test.c")
set(WHEEL_TIMER_TEST_SRC "WheelTimerDemo.c")
target_compile_definitions(wheeltimer PRIVATE _POSIX_C_SOURCE=199309L)
add_executable(${TIMERLIB_TEST_EXE}
${TIMERLIB_TEST_SRC})
add_executable(${WHEELTIMER_TEST_EXE}
${WHEEL_TIMER_TEST_SRC})
target_link_libraries(${TIMERLIB_TEST_EXE} PUBLIC
${TIMER_LIB})
target_link_libraries(${WHEELTIMER_TEST_EXE} PUBLIC
${WHEELTIMER_LIB})
target_include_directories(${TIMERLIB_TEST_EXE} PUBLIC
${HEADER_DIR})
${HEADER_DIR})
target_include_directories(${WHEELTIMER_TEST_EXE} PUBLIC
${HEADER_DIR})

53
test/WheelTimerDemo.c Normal file
View File

@@ -0,0 +1,53 @@
#include <stdio.h>
#include <WheelTimer.h>
#include <string.h>
#define WHEEL_SIZE 10
#define WHEEL_TIMER_CLOCK_TIC_INTERVAL 1
/* Application routine to be (indirectly) invoked by Wheel timer.
* It could be of any prototype*/
void
print_hello(char* S) {
printf("%s\n", S);
}
/* But Only routines (Events) which have prototype : void *(fn)(void *arg, int arg_size)
* could be registered with wheel timer. Therefore, we need to encapsulate
* the actual routine print_hello() to be invoked inside the routine of
* void *(fn)(void *arg, int arg_size) prototype. It is the wrapper which will be registered
* with wheel timer and invoked by wheel timer. We will unwrap the argument and invoke the actual
* appln routine with correct arguments. This technique is called 'Masking of routines'*/
void wrapper_print_hello(void* arg, int arg_size) {
char* S = (char*)arg;
print_hello(S);
}
int
main(int argc, char** argv) {
/*create a wheel timer object*/
wheel_timer_t* wt = init_wheel_timer(WHEEL_SIZE, WHEEL_TIMER_CLOCK_TIC_INTERVAL);
/*start the wheel timer thread*/
start_wheel_timer(wt);
/*Now Wheel timer has started running in a separte thread.
* Register the events to be triggered with Wheel timer now.*/
wheel_timer_elem_t* wt_elem =
register_app_event(wt, wrapper_print_hello, "MyString",
strlen("MyString"),
5, /*wrapper_print_hello fn will be called after every 5 seconds*/
1); /*1 indefinitely, 0 only once : call for wrapper_print_hello*/
wt_elem =
register_app_event(wt, wrapper_print_hello, "www.csepracticals.com",
strlen("www.csepracticals.com"),
3, /*wrapper_print_hello fn will be called after every 5 seconds*/
1); /*1 indefinitely, 0 only once : call for wrapper_print_hello*/
/*stop the main program from gettin terminated, otherwise wheel timer
* thread we created will also get terminated*/
scanf("\n");
return 0;
}