mirror of
https://github.com/Hizenberg469/WheelTimer.git
synced 2026-04-19 18:52:22 +03:00
Timerlib Integrated with Wheel Timer
This commit is contained in:
@@ -5,10 +5,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include "timerlib.h"
|
||||||
#define TH_JOINABLE 1
|
|
||||||
#define TH_DETACHED 0
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
insert_wt_elem_in_slot(void *data1, void *data2){
|
insert_wt_elem_in_slot(void *data1, void *data2){
|
||||||
@@ -25,25 +22,6 @@ insert_wt_elem_in_slot(void *data1, void *data2){
|
|||||||
return 0;
|
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
|
static void
|
||||||
process_wt_reschedule_slotlist(wheel_timer_t *wt){
|
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));
|
WT_UNLOCK_SLOT_LIST(WT_GET_RESCHD_SLOTLIST(wt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
static void *
|
wheel_fn(Timer_t *timer, 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;
|
||||||
slotlist_t *slot_list = NULL;
|
slotlist_t *slot_list = NULL;
|
||||||
glthread_t *curr;
|
glthread_t *curr;
|
||||||
|
|
||||||
while(1){
|
wt->current_clock_tic++;
|
||||||
|
if(wt->current_clock_tic == wt->wheel_size){
|
||||||
wt->current_clock_tic++;
|
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);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
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
|
static void
|
||||||
_wt_elem_reschedule(wheel_timer_t *wt,
|
_wt_elem_reschedule(wheel_timer_t *wt,
|
||||||
wheel_timer_elem_t *wt_elem,
|
wheel_timer_elem_t *wt_elem,
|
||||||
@@ -179,12 +178,14 @@ _wt_elem_reschedule(wheel_timer_t *wt,
|
|||||||
case WTELEM_DELETE:
|
case WTELEM_DELETE:
|
||||||
|
|
||||||
wt_elem->new_time_interval = new_time_interval;
|
wt_elem->new_time_interval = new_time_interval;
|
||||||
|
pause_timer(wt->wheel_thread);
|
||||||
WT_LOCK_SLOT_LIST(WT_GET_RESCHD_SLOTLIST(wt));
|
WT_LOCK_SLOT_LIST(WT_GET_RESCHD_SLOTLIST(wt));
|
||||||
wt_elem->opcode = opcode;
|
wt_elem->opcode = opcode;
|
||||||
remove_glthread(&wt_elem->reschedule_glue);
|
remove_glthread(&wt_elem->reschedule_glue);
|
||||||
glthread_add_next(WT_GET_RESCHD_SLOTLIST_HEAD(wt),
|
glthread_add_next(WT_GET_RESCHD_SLOTLIST_HEAD(wt),
|
||||||
&wt_elem->reschedule_glue);
|
&wt_elem->reschedule_glue);
|
||||||
WT_UNLOCK_SLOT_LIST(WT_GET_RESCHD_SLOTLIST(wt));
|
WT_UNLOCK_SLOT_LIST(WT_GET_RESCHD_SLOTLIST(wt));
|
||||||
|
resume_timer(wt->wheel_thread);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
@@ -300,11 +301,7 @@ print_wheel_timer(wheel_timer_t *wt){
|
|||||||
void
|
void
|
||||||
start_wheel_timer(wheel_timer_t *wt){
|
start_wheel_timer(wheel_timer_t *wt){
|
||||||
|
|
||||||
if (pthread_create(&wt->wheel_thread, NULL, wheel_fn, (void*)wt))
|
start_timer(wt->wheel_thread);
|
||||||
{
|
|
||||||
printf("Wheel Timer Thread initialization failed, exiting ... \n");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -336,3 +333,11 @@ hrs_min_sec_format(unsigned int seconds){
|
|||||||
return time_f;
|
return time_f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cancel_wheel_timer(wheel_timer_t *wt){
|
||||||
|
|
||||||
|
if(wt->wheel_thread){
|
||||||
|
cancel_timer(wt->wheel_thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#define __WHEEL_TIMER__
|
#define __WHEEL_TIMER__
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include "timerlib.h"
|
||||||
#include "gluethread/glthread.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;
|
||||||
@@ -45,7 +46,7 @@ typedef struct _wheel_timer_t {
|
|||||||
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;
|
Timer_t *wheel_thread;
|
||||||
slotlist_t reschd_list;
|
slotlist_t reschd_list;
|
||||||
unsigned int no_of_wt_elem;
|
unsigned int no_of_wt_elem;
|
||||||
slotlist_t slotlist[0];
|
slotlist_t slotlist[0];
|
||||||
53
WheelTimer/libtimer/WheelTimerDemo.c
Normal file
53
WheelTimer/libtimer/WheelTimerDemo.c
Normal 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, "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;
|
||||||
|
}
|
||||||
@@ -3,3 +3,7 @@ rm *exe
|
|||||||
gcc -g -c timerlib.c -o timerlib.o
|
gcc -g -c timerlib.c -o timerlib.o
|
||||||
gcc -g -c timerlib_test.c -o timerlib_test.o
|
gcc -g -c timerlib_test.c -o timerlib_test.o
|
||||||
gcc -g timerlib.o timerlib_test.o -o exe -lrt
|
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
|
||||||
|
|||||||
@@ -183,8 +183,9 @@ cancel_timer(Timer_t *timer){
|
|||||||
void
|
void
|
||||||
pause_timer(Timer_t *timer){
|
pause_timer(Timer_t *timer){
|
||||||
|
|
||||||
assert(timer->timer_state == TIMER_RUNNING);
|
if ( timer_get_current_state(timer) == TIMER_PAUSED)
|
||||||
|
return;
|
||||||
|
|
||||||
timer->time_remaining =
|
timer->time_remaining =
|
||||||
timer_get_time_remaining_in_mill_sec(timer);
|
timer_get_time_remaining_in_mill_sec(timer);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user