diff --git a/WheelTimer/WheelTimer.c b/WheelTimer/WheelTimer.c index 6b5e000..7c54218 100644 --- a/WheelTimer/WheelTimer.c +++ b/WheelTimer/WheelTimer.c @@ -4,141 +4,253 @@ #include #include #include -#include "LinkedListApi.h" +#include #define TH_JOINABLE 1 #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* init_wheel_timer(int wheel_size, int clock_tic_interval){ 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->wheel_size = wheel_size; - pthread_mutex_init(&wt->wheel_timer_mutex, NULL); - wt->wheel_thread = calloc(1, sizeof(_pthread_t)); - pthread_init(wt->wheel_thread, 0, TH_DETACHED); + memset(&(wt->wheel_thread), 0, sizeof(wheel_timer_t)); int i = 0; - for(; i < wheel_size; i++) - wt->slots[i] = init_singly_ll(); - + 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; } -void -de_register_app_event(wheel_timer_t *wt, wheel_timer_elem_t *wt_elem){ - if(!wt_elem) return; - pause_wheel_timer(wt); - wt_elem->is_alive = 0; - resume_wheel_timer(wt); +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* +static void * wheel_fn(void *arg){ wheel_timer_t *wt = (wheel_timer_t *)arg; wheel_timer_elem_t *wt_elem = NULL; int absolute_slot_no = 0, i =0; - ll_t *slot_list = NULL; - singly_ll_node_t *head = NULL, *next_node = NULL; + slotlist_t *slot_list = NULL; + glthread_t *curr; while(1){ - wt->current_clock_tic++; - wt->current_clock_tic = (wt->current_clock_tic % wt->wheel_size); - if(wt->current_clock_tic == 0) - wt->current_cycle_no++; + + 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); - tentative_wait(wt->wheel_thread, &wt->wheel_timer_mutex); - slot_list = wt->slots[wt->current_clock_tic]; - head = GET_HEAD_SINGLY_LL(slot_list); - int node_count = GET_NODE_COUNT_SINGLY_LL(slot_list); + slot_list = WT_SLOTLIST(wt, wt->current_clock_tic); 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){ - singly_ll_remove_node(slot_list, head); - free_wheel_timer_element(wt_elem); - free(head); - head = next_node; - continue; - } - + + 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*/ - 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_slot_no = next_abs_slot_no % wt->wheel_size; wt_elem->execute_cycle_no = next_cycle_no; - if(next_slot_no == wt->current_clock_tic){ - head = next_node; - continue; - } - singly_ll_remove_node(slot_list, head); - singly_ll_add_node(wt->slots[next_slot_no], head); - } - else{ - free_wheel_timer_element((wheel_timer_elem_t *)head->data); - singly_ll_delete_node(slot_list, head); + 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++; } } - head = next_node; - } + else + break; + } ITERATE_GLTHREAD_END(slot_list, curr) + process_wt_reschedule_slotlist(wt); } 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 * register_app_event(wheel_timer_t *wt, - app_call_back call_back, - void *arg, - int arg_size, - int time_interval, - char is_recursive){ + 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->time_interval = time_interval; wt_elem->app_callback = call_back; - wt_elem->arg = calloc(1, arg_size); - memcpy(wt_elem->arg, arg, arg_size); - wt_elem->arg_size = arg_size; + 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; +} - /*Stop the Wheel timer Thread here*/ - pause_wheel_timer(wt); +void +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); - 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); + _wt_elem_reschedule(wt, wt_elem, 0, WTELEM_DELETE); +} - resume_wheel_timer(wt); - return wt_elem; +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); } @@ -146,46 +258,49 @@ free_wheel_timer_element(wheel_timer_elem_t *wt_elem){ void 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; - singly_ll_node_t *head = 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->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 = wt->slots[i]; - printf(" slot_list[%d] : count : %d\n", i, GET_NODE_COUNT_SINGLY_LL(slot_list)); - head = GET_HEAD_SINGLY_LL(slot_list); - for(j = 0 ; j < GET_NODE_COUNT_SINGLY_LL(slot_list); j++){ - wt_elem = (wheel_timer_elem_t *)head->data; - if(!wt_elem){ - printf(" NULL\n"); - head = GET_NEXT_NODE_SINGLY_LL(head); - continue; - } - printf(" wt_elem->time_interval = %d\n", wt_elem->time_interval); + 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->arg = %p\n", wt_elem->arg); 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 start_wheel_timer(wheel_timer_t *wt){ - _pthread_t *thread = wt->wheel_thread; - if (pthread_create(&thread->pthread_handle, &thread->attr, wheel_fn, (void*)wt)) + if (pthread_create(&wt->wheel_thread, NULL, wheel_fn, (void*)wt)) { printf("Wheel Timer Thread initialization failed, exiting ... \n"); exit(0); @@ -198,21 +313,26 @@ reset_wheel_timer(wheel_timer_t *wt){ wt->current_cycle_no = 0; } -void -pause_wheel_timer(wheel_timer_t *wt){ - send_wait_order(wt->wheel_thread); + +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 -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; -} diff --git a/WheelTimer/WheelTimer.h b/WheelTimer/WheelTimer.h index 251c199..615a913 100644 --- a/WheelTimer/WheelTimer.h +++ b/WheelTimer/WheelTimer.h @@ -1,40 +1,110 @@ #ifndef __WHEEL_TIMER__ #define __WHEEL_TIMER__ -#include "threadApi.h" + +#include +#include "gluethread/glthread.h" typedef struct _wheel_timer_elem_t wheel_timer_elem_t; 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{ + + 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; - /* control param*/ - char is_alive; + 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; - _pthread_t *wheel_thread; - pthread_mutex_t wheel_timer_mutex; - ll_t *slots[0]; + pthread_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); -#define GET_WT_CURRENT_ABS_SLOT_NO(wt) ((wt->current_cycle_no * wt->wheel_size) + wt->current_clock_tic) -void -cleanup_wheel_timer(wheel_timer_t *wt); +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, @@ -44,12 +114,13 @@ register_app_event(wheel_timer_t *wt, 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_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 free_wheel_timer_element(wheel_timer_elem_t *wt_elem); @@ -60,16 +131,13 @@ print_wheel_timer(wheel_timer_t *wt); void start_wheel_timer(wheel_timer_t *wt); -void -pause_wheel_timer(wheel_timer_t *wt); - void cancel_wheel_timer(wheel_timer_t *wt); void reset_wheel_timer(wheel_timer_t *wt); -void -resume_wheel_timer(wheel_timer_t *wt); +char* +hrs_min_sec_format(unsigned int seconds); #endif diff --git a/WheelTimer/gluethread/glthread.c b/WheelTimer/gluethread/glthread.c new file mode 100644 index 0000000..97b9f7c --- /dev/null +++ b/WheelTimer/gluethread/glthread.c @@ -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 . + * + * ===================================================================================== + */ + + +#include "glthread.h" +#include + +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 diff --git a/WheelTimer/gluethread/glthread.h b/WheelTimer/gluethread/glthread.h new file mode 100644 index 0000000..32f0af7 --- /dev/null +++ b/WheelTimer/gluethread/glthread.h @@ -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 . + * + * ===================================================================================== + */ + +#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__ */ diff --git a/WheelTimer/gluethread/test.c b/WheelTimer/gluethread/test.c new file mode 100644 index 0000000..0e68b1d --- /dev/null +++ b/WheelTimer/gluethread/test.c @@ -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 . + * + * ===================================================================================== + */ + +#include "glthread.h" +#include +#include +#include + +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; +} diff --git a/WheelTimer/main.c b/WheelTimer/main.c index 41ca9bc..58f8b64 100644 --- a/WheelTimer/main.c +++ b/WheelTimer/main.c @@ -1,15 +1,12 @@ -#include "WheelTimer.h" #include #include #include +#include "WheelTimer.h" - -#define MAX_NUMBER_APP_THREADS 1 #define WHEEL_SIZE 15 #define WHEEL_TIMER_CLOCK_TIC_INTERVAL 1 // sec -/*Import Library global Variables*/ -extern blocked_pool_t gl_blocked_th_pool; +wheel_timer_t *wt; void generate_general_query(int vlan){ @@ -77,7 +74,7 @@ main_menu(wheel_timer_t *wt){ int new_time_interval = 0; printf("Enter 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; case 11: @@ -85,7 +82,7 @@ main_menu(wheel_timer_t *wt){ int new_time_interval = 0; printf("Enter 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; case 12: @@ -93,7 +90,7 @@ main_menu(wheel_timer_t *wt){ int new_time_interval = 0; printf("Enter 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; case 6: @@ -173,9 +170,7 @@ main_menu(wheel_timer_t *wt){ int main(int argc, char **argv){ - init_blocked_pool(&gl_blocked_th_pool, MAX_NUMBER_APP_THREADS); - wheel_timer_t *wt = - init_wheel_timer(WHEEL_SIZE, WHEEL_TIMER_CLOCK_TIC_INTERVAL); + wt = init_wheel_timer(WHEEL_SIZE, WHEEL_TIMER_CLOCK_TIC_INTERVAL); start_wheel_timer(wt); /* WT thread is in DETACHED MODE, so below call is useless*/ diff --git a/WheelTimer/readme b/WheelTimer/readme index e512f97..e00a876 100644 --- a/WheelTimer/readme +++ b/WheelTimer/readme @@ -2,6 +2,7 @@ This is the simple demostration of WheelTimer in C 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