From f64c44275cda9c2d916f8ebdc3cbb0a3831d32f4 Mon Sep 17 00:00:00 2001 From: Abhishek Sagar Date: Wed, 14 Oct 2020 22:58:55 -0700 Subject: [PATCH] Timerlib Integrated with Wheel Timer --- .../libtimer/{WheelTimer => }/WheelTimer.c | 165 +++++++++--------- .../libtimer/{WheelTimer => }/WheelTimer.h | 3 +- WheelTimer/libtimer/WheelTimerDemo.c | 53 ++++++ WheelTimer/libtimer/compile.sh | 4 + WheelTimer/libtimer/timerlib.c | 5 +- 5 files changed, 147 insertions(+), 83 deletions(-) rename WheelTimer/libtimer/{WheelTimer => }/WheelTimer.c (79%) rename WheelTimer/libtimer/{WheelTimer => }/WheelTimer.h (98%) create mode 100644 WheelTimer/libtimer/WheelTimerDemo.c diff --git a/WheelTimer/libtimer/WheelTimer/WheelTimer.c b/WheelTimer/libtimer/WheelTimer.c similarity index 79% rename from WheelTimer/libtimer/WheelTimer/WheelTimer.c rename to WheelTimer/libtimer/WheelTimer.c index 7c54218..2576d66 100644 --- a/WheelTimer/libtimer/WheelTimer/WheelTimer.c +++ b/WheelTimer/libtimer/WheelTimer.c @@ -5,10 +5,7 @@ #include #include #include - -#define TH_JOINABLE 1 -#define TH_DETACHED 0 - +#include "timerlib.h" int insert_wt_elem_in_slot(void *data1, void *data2){ @@ -25,25 +22,6 @@ insert_wt_elem_in_slot(void *data1, void *data2){ 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){ @@ -100,65 +78,86 @@ process_wt_reschedule_slotlist(wheel_timer_t *wt){ WT_UNLOCK_SLOT_LIST(WT_GET_RESCHD_SLOTLIST(wt)); } - -static void * -wheel_fn(void *arg){ +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; + 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); + wt->current_clock_tic++; + if(wt->current_clock_tic == wt->wheel_size){ + wt->current_clock_tic = 0; + wt->current_cycle_no++; } - return NULL; + + 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, @@ -179,12 +178,14 @@ _wt_elem_reschedule(wheel_timer_t *wt, 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)); + &wt_elem->reschedule_glue); + WT_UNLOCK_SLOT_LIST(WT_GET_RESCHD_SLOTLIST(wt)); + resume_timer(wt->wheel_thread); break; default: assert(0); @@ -300,11 +301,7 @@ print_wheel_timer(wheel_timer_t *wt){ 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); - } + start_timer(wt->wheel_thread); } void @@ -336,3 +333,11 @@ hrs_min_sec_format(unsigned int seconds){ return time_f; } +void +cancel_wheel_timer(wheel_timer_t *wt){ + + if(wt->wheel_thread){ + cancel_timer(wt->wheel_thread); + } +} + diff --git a/WheelTimer/libtimer/WheelTimer/WheelTimer.h b/WheelTimer/libtimer/WheelTimer.h similarity index 98% rename from WheelTimer/libtimer/WheelTimer/WheelTimer.h rename to WheelTimer/libtimer/WheelTimer.h index 615a913..0a5264b 100644 --- a/WheelTimer/libtimer/WheelTimer/WheelTimer.h +++ b/WheelTimer/libtimer/WheelTimer.h @@ -2,6 +2,7 @@ #define __WHEEL_TIMER__ #include +#include "timerlib.h" #include "gluethread/glthread.h" typedef struct _wheel_timer_elem_t wheel_timer_elem_t; @@ -45,7 +46,7 @@ typedef struct _wheel_timer_t { int clock_tic_interval; int wheel_size; int current_cycle_no; - pthread_t wheel_thread; + Timer_t *wheel_thread; slotlist_t reschd_list; unsigned int no_of_wt_elem; slotlist_t slotlist[0]; diff --git a/WheelTimer/libtimer/WheelTimerDemo.c b/WheelTimer/libtimer/WheelTimerDemo.c new file mode 100644 index 0000000..4f3d6fb --- /dev/null +++ b/WheelTimer/libtimer/WheelTimerDemo.c @@ -0,0 +1,53 @@ +#include +#include "WheelTimer.h" +#include + +#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, "Udemy", + strlen("Udemy"), + 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; +} diff --git a/WheelTimer/libtimer/compile.sh b/WheelTimer/libtimer/compile.sh index 0d219b3..43f761e 100644 --- a/WheelTimer/libtimer/compile.sh +++ b/WheelTimer/libtimer/compile.sh @@ -3,3 +3,7 @@ rm *exe gcc -g -c timerlib.c -o timerlib.o gcc -g -c timerlib_test.c -o timerlib_test.o gcc -g timerlib.o timerlib_test.o -o exe -lrt +gcc -g -c WheelTimer.c -o WheelTimer.o +gcc -g -c WheelTimerDemo.c -o WheelTimerDemo.o +gcc -g -c gluethread/glthread.c -o gluethread/glthread.o +gcc -g WheelTimerDemo.o WheelTimer.o timerlib.o gluethread/glthread.o -o WheelTimerDemo.exe -lrt diff --git a/WheelTimer/libtimer/timerlib.c b/WheelTimer/libtimer/timerlib.c index 1968a90..7e7ea22 100644 --- a/WheelTimer/libtimer/timerlib.c +++ b/WheelTimer/libtimer/timerlib.c @@ -183,8 +183,9 @@ cancel_timer(Timer_t *timer){ void pause_timer(Timer_t *timer){ - assert(timer->timer_state == TIMER_RUNNING); - + if ( timer_get_current_state(timer) == TIMER_PAUSED) + return; + timer->time_remaining = timer_get_time_remaining_in_mill_sec(timer);