diff --git a/WheelTimer/libtimer/compile.sh b/WheelTimer/libtimer/compile.sh new file mode 100644 index 0000000..0d219b3 --- /dev/null +++ b/WheelTimer/libtimer/compile.sh @@ -0,0 +1,5 @@ +rm *o +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 diff --git a/WheelTimer/libtimer/timerlib.c b/WheelTimer/libtimer/timerlib.c index 4d782b3..c739162 100644 --- a/WheelTimer/libtimer/timerlib.c +++ b/WheelTimer/libtimer/timerlib.c @@ -23,7 +23,7 @@ #include #include "timerlib.h" -static unsigned long +unsigned long timespec_to_millisec( struct timespec *time){ @@ -34,7 +34,7 @@ timespec_to_millisec( return milli_sec; } -static void +void timer_fill_itimerspec(struct timespec *ts, unsigned long msec) { @@ -54,13 +54,23 @@ static void timer_callback_wrapper(union sigval arg){ Timer_t *timer = (Timer_t *)(arg.sival_ptr); + timer->invocation_counter++; + if(timer->thresdhold && (timer->invocation_counter > timer->thresdhold)){ cancel_timer(timer); return; } + (timer->cb)(timer, timer->user_arg); + + if(timer->exponential_backoff){ + + assert(timer->exp_back_off_time); + reschedule_timer(timer, + timer->exp_back_off_time *= 2, 0); + } } @@ -72,8 +82,8 @@ setup_timer( unsigned long exp_timer, /* First expiration time interval in msec */ unsigned long sec_exp_timer, /* Subsequent expiration time interval in msec */ uint32_t threshold, /* Max no of expirations, 0 for infinite*/ - void *user_arg){ /* Arg to timer callback */ - + void *user_arg, /* Arg to timer callback */ + bool exponential_backoff){ /* Is Timer Exp backoff*/ Timer_t *timer = calloc(1, sizeof(Timer_t)); timer->posix_timer = calloc(1, sizeof(timer_t)); @@ -84,6 +94,7 @@ setup_timer( timer->cb = timer_cb; timer->thresdhold = threshold; timer->timer_state = TIMER_INIT; + timer->exponential_backoff = exponential_backoff; /* Sanity checks */ assert(timer->cb); /* Mandatory */ @@ -102,8 +113,15 @@ setup_timer( assert(rc >= 0); timer_fill_itimerspec(&timer->ts.it_value, timer->exp_timer); - timer_fill_itimerspec(&timer->ts.it_interval, timer->sec_exp_timer); + if(!timer->exponential_backoff){ + timer_fill_itimerspec(&timer->ts.it_interval, timer->sec_exp_timer); + timer->exp_back_off_time = 0; + } + else{ + timer->exp_back_off_time = timespec_to_millisec(&timer->ts.it_value); + timer_fill_itimerspec(&timer->ts.it_interval, 0); + } return timer; } @@ -141,7 +159,8 @@ cancel_timer(Timer_t *timer){ /* Only Paused or running timer can be cancelled */ timer_fill_itimerspec(&timer->ts.it_value, 0); timer_fill_itimerspec(&timer->ts.it_interval, 0); - timer->time_remaining = 0; + timer->time_remaining = 0; + timer->invocation_counter = 0; start_timer(timer); timer->timer_state = TIMER_CANCELLED; } @@ -156,9 +175,7 @@ pause_timer(Timer_t *timer){ timer_get_time_remaining_in_mill_sec(timer); timer_fill_itimerspec(&timer->ts.it_value, 0); - - /* Do not reset the interval */ - //timer_fill_itimerspec(&timer->ts.it_interval, 0); + timer_fill_itimerspec(&timer->ts.it_interval, 0); start_timer(timer); @@ -172,9 +189,9 @@ resume_timer(Timer_t *timer){ assert(timer->timer_state == TIMER_PAUSED); timer_fill_itimerspec(&timer->ts.it_value, timer->time_remaining); + timer_fill_itimerspec(&timer->ts.it_interval, timer->sec_exp_timer); timer->time_remaining = 0; start_timer(timer); - timer->timer_state = TIMER_RUNNING; } unsigned long @@ -207,40 +224,61 @@ timer_get_time_remaining_in_mill_sec(Timer_t *timer){ void restart_timer(Timer_t *timer){ - if(timer->timer_state != TIMER_PAUSED || - timer->timer_state != TIMER_RUNNING) { - - assert(0); - } + assert(timer->timer_state != TIMER_DELETED); cancel_timer(timer); timer_fill_itimerspec(&timer->ts.it_value, timer->exp_timer); + + if(!timer->exponential_backoff) timer_fill_itimerspec(&timer->ts.it_interval, timer->sec_exp_timer); + else + timer_fill_itimerspec(&timer->ts.it_interval, 0); + timer->invocation_counter = 0; timer->time_remaining = 0; + timer->exp_back_off_time = timer->exp_timer; start_timer(timer); } -int +void reschedule_timer(Timer_t *timer, unsigned long exp_ti, unsigned long sec_exp_ti){ + uint32_t invocation_counter; + if(timer->timer_state == TIMER_DELETED) assert(0); + invocation_counter = timer->invocation_counter; + if(timer->timer_state != TIMER_CANCELLED) { cancel_timer(timer); } - timer->exp_timer = exp_ti; - timer->sec_exp_timer = sec_exp_ti; - timer->invocation_counter = 0; + timer->invocation_counter = invocation_counter; + timer_fill_itimerspec(&timer->ts.it_value, exp_ti); - timer_fill_itimerspec(&timer->ts.it_interval, sec_exp_ti); + + if(!timer->exponential_backoff){ + timer_fill_itimerspec(&timer->ts.it_interval, sec_exp_ti); + } + else{ + timer_fill_itimerspec(&timer->ts.it_interval, 0); + timer->exp_back_off_time = exp_ti; + } + timer->time_remaining = 0; start_timer(timer); - timer->timer_state = TIMER_RUNNING; +} + +void +print_timer(Timer_t *timer){ + + printf("Counter = %u, time remaining = %lu, state = %d\n", + timer->invocation_counter, + timer_get_time_remaining_in_mill_sec(timer), + timer_get_current_state(timer)); } diff --git a/WheelTimer/libtimer/timerlib.h b/WheelTimer/libtimer/timerlib.h index 029fa46..6c9c78f 100644 --- a/WheelTimer/libtimer/timerlib.h +++ b/WheelTimer/libtimer/timerlib.h @@ -24,6 +24,7 @@ #include #include #include +#include typedef enum{ @@ -43,12 +44,14 @@ typedef struct Timer_{ unsigned long sec_exp_timer; /* in milli-sec */ uint32_t thresdhold; /* No of times to invoke the timer callback */ void (*cb)(struct Timer_ *, void *); /* Timer Callback */ + bool exponential_backoff; /* place holder value to store * dynamic attributes of timer */ unsigned long time_remaining; /* Time left for paused timer for next expiration */ uint32_t invocation_counter; struct itimerspec ts; + unsigned long exp_back_off_time; TIMER_STATE_T timer_state; } Timer_t; @@ -65,7 +68,24 @@ setup_timer( /* Max no of expirations, 0 for infinite*/ uint32_t, /* Arg to timer callback */ - void *); + void *, + /* Is timer Exp back off */ + bool); + +static inline void +timer_delete_user_data(Timer_t *timer){ + + if(timer->user_arg) { + free(timer->user_arg); + timer->user_arg = NULL; + } +} + +static inline TIMER_STATE_T +timer_get_current_state(Timer_t *timer){ + + return timer->timer_state; +} void start_timer(Timer_t *timer); @@ -92,8 +112,19 @@ timer_get_time_remaining_in_mill_sec(Timer_t *timer); void restart_timer(Timer_t *timer); -int +void reschedule_timer(Timer_t *timer, unsigned long exp_ti, unsigned long sec_exp_ti); + +void +print_timer(Timer_t *timer); + +unsigned long +timespec_to_millisec( + struct timespec *time); + +void +timer_fill_itimerspec(struct timespec *ts, + unsigned long msec); #endif /* __TIMER_WRAP__ */ diff --git a/WheelTimer/libtimer/timerlib_test.c b/WheelTimer/libtimer/timerlib_test.c new file mode 100644 index 0000000..f70bc3a --- /dev/null +++ b/WheelTimer/libtimer/timerlib_test.c @@ -0,0 +1,71 @@ +#include +#include "timerlib.h" + +static void +app_cb(Timer_t *timer, void *user_data){ + + time_t t; + time(&t); + printf("%s ",ctime(&t)); + printf("%s() invoked ... name = %s, counter = %u, Threshold = %u, next fire time = %lu\n", + __FUNCTION__, (char *)user_data, timer->invocation_counter, + timer->thresdhold, timespec_to_millisec(&timer->ts.it_value)); +} + +int +main(int argc, char **argv){ + + char *name = "Abhishek"; + + Timer_t *timer = setup_timer(app_cb, 1000 , 1000, 4, name, true); + start_timer(timer); + + printf("1. Pause Timer\n"); + printf("2. Resume Timer\n"); + printf("3. Restart timer\n"); + printf("4. Reschedule timer\n"); + printf("5. Delete timer\n"); + printf("6. Cancel Timer\n"); + printf("7. Get Remaining Time\n"); + printf("8. Print Timer State\n"); + + int choice; + choice = 0; + + while(1){ + scanf("%d", &choice); + + switch(choice){ + + case 1: + pause_timer(timer); + break; + case 2: + resume_timer(timer); + break; + case 3: + restart_timer(timer); + break; + case 4: + reschedule_timer(timer, + timer->exp_timer, + timer->sec_exp_timer); + break; + case 5: + delete_timer(timer); + break; + case 6: + cancel_timer(timer); + break; + case 7: + printf("Rem Time = %lu\n", timer_get_time_remaining_in_mill_sec(timer)); + break; + case 8: + print_timer(timer); + break; + deafault: ; + } + } + pause(); + return 0; +}