diff --git a/CMakeLists.txt b/CMakeLists.txt index ed7c1b7..aa412f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,4 +34,4 @@ set(SOURCE_DIR ${CMAKE_SOURCE_DIR}/src) #Adding Sub-directory having CMakeLists.txt... add_subdirectory(src) -#add_subdirectory(test) \ No newline at end of file +add_subdirectory(test) \ No newline at end of file diff --git a/include/event_loop.h b/include/event_loop.h index b0ef942..de6e601 100644 --- a/include/event_loop.h +++ b/include/event_loop.h @@ -1,11 +1,13 @@ #ifndef __EV_LOOP__ #define __EV_LOOP__ +#include + typedef struct task_ task_t; typedef struct event_loop_ event_loop_t; -typedef EL_RES_T(*event_cbk)(void*); +typedef void (*event_cbk)(void*); struct task_ { @@ -23,7 +25,7 @@ typedef enum { struct event_loop_ { /* head to the start of the task array */ - struct task_* task_array_head[TASK_PRIORITY_MAX]; + struct task_* task_array_head; /* Mutex to enforce Mutual exclusion enqueue/Deque * Operation in task array. Also used to update event loop * attributes in mutual exclusive way @@ -40,4 +42,13 @@ struct event_loop_ { struct task_* current_task; }; +void +event_loop_init(event_loop_t* el); + +void +event_loop_run(event_loop_t* el); + +task_t* +task_create_new_job(event_loop_t* el, event_cbk cbk, void* arg); + #endif \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5de2a47..f08da6e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,4 +4,16 @@ add_library(${EVENT_LOOP_LIB} STATIC ${EVENT_LOOP_SRC}) target_include_directories(${EVENT_LOOP_LIB} PUBLIC - ${HEADER_DIR}) \ No newline at end of file + ${HEADER_DIR}) + +#Linking dependent library... + +if( NOT (CMAKE_SYSTEM_NAME STREQUAL "Linux") ) + message(FATAL_ERROR "It's not a Unix-based system.\n \ + POSIX Library will not compile in this project.\n") +endif() +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + +target_link_libraries(${EVENT_LOOP_LIB} PUBLIC + Threads::Threads) diff --git a/src/event_loop.c b/src/event_loop.c index e69de29..4f16dcf 100644 --- a/src/event_loop.c +++ b/src/event_loop.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include + +static bool el_debug = true; + + +static task_t* +event_loop_get_next_task_to_run(event_loop_t* el) { + + task_t* task; + if (!el->task_array_head) return NULL; + task = el->task_array_head; + el->task_array_head = task->right; + if (el->task_array_head) { + el->task_array_head->left = NULL; + } + task->left = NULL; + task->right = NULL; + return task; +} + +static void +event_loop_add_task_in_task_array( + event_loop_t* el, + task_t* new_task) { + + task_t* task, * prev_task; + + prev_task = NULL; + + task = el->task_array_head; + while (task) { + prev_task = task; + task = task->right; + } + if (prev_task) { + prev_task->right = new_task; + new_task->left = prev_task; + } + else { + el->task_array_head = new_task; + } +} + +static bool +task_is_present_in_task_array(task_t* task) { + + return !(task->left == NULL && task->right == NULL); +} + +/* one more API added later */ + +static void +event_loop_remove_task_from_task_array(event_loop_t* el, task_t* task) { + + if (el->task_array_head == task) { + el->task_array_head = task->right; + } + + if (!task->left) { + if (task->right) { + task->right->left = NULL; + task->right = 0; + return; + } + return; + } + if (!task->right) { + task->left->right = NULL; + task->left = NULL; + return; + } + + task->left->right = task->right; + task->right->left = task->left; + task->left = 0; + task->right = 0; +} + +void +event_loop_init(event_loop_t* el) { + + el->task_array_head = NULL; + pthread_mutex_init(&el->ev_loop_mutex, NULL); + el->ev_loop_state = EV_LOOP_IDLE; + pthread_cond_init(&el->ev_loop_cv, NULL); + el->current_task = NULL; +} + +static void +event_loop_schedule_task(event_loop_t* el, task_t* task) { + + pthread_mutex_lock(&el->ev_loop_mutex); + + event_loop_add_task_in_task_array(el, task); + + if (el->ev_loop_state == EV_LOOP_BUSY) { + pthread_mutex_unlock(&el->ev_loop_mutex); + return; + } + + pthread_cond_signal(&el->ev_loop_cv); + pthread_mutex_unlock(&el->ev_loop_mutex); +} + + +static void* event_loop_thread(void* arg) { + + task_t* task; + event_loop_t* el = (event_loop_t*)arg; + while (1) { + /* Lock the event Loop Mutex */ + pthread_mutex_lock(&el->ev_loop_mutex); + + while ((task = event_loop_get_next_task_to_run(el)) == NULL) { + + /* Event Loop thread do not have any task to fire + , suspended the event loop thread*/ + if (el_debug) { + printf("Task Array Empty, EL thread is suspending\n"); + } + el->ev_loop_state = EV_LOOP_IDLE; + pthread_cond_wait(&el->ev_loop_cv, &el->ev_loop_mutex); + /* We are here when event loop thread recvs signal. On receiving the + signal, go back, fetch the new task from task array + again and decide if we want to block again or fire the task*/ + } + el->ev_loop_state = EV_LOOP_BUSY; + /* We are done with the task array, unlock it now, object of interest + is already detached from task array*/ + pthread_mutex_unlock(&el->ev_loop_mutex); + + if (el_debug) { + printf("EL Thread woken up, Firing the task\n"); + } + + /* Fire the task now */ + el->current_task = task; + task->cbk(task->arg); + el->current_task = NULL; + } + + return NULL; +} + +task_t* +task_create_new_job(event_loop_t* el, event_cbk cbk, void* arg) { + + task_t* task = (task_t*)calloc(1, sizeof(task_t)); + task->arg = arg; + task->cbk = cbk; + task->left = NULL; + task->right = NULL; + event_loop_schedule_task(el, task); + return task; +} + +void +event_loop_run(event_loop_t* el) { + + pthread_attr_t attr; + + assert(el->thread == NULL); + + el->thread = (pthread_t*)calloc(1, sizeof(pthread_t)); + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + pthread_create(el->thread, &attr, + event_loop_thread, (void*)el); + +} + + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..5419696 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,11 @@ +set(EVENT_LOOP_APP evloop_app) +set(EV_LOOP_APP_SRC "evloop_app.c") + +add_executable(${EVENT_LOOP_APP} + ${EV_LOOP_APP_SRC}) + +target_link_libraries(${EVENT_LOOP_APP} PUBLIC + ${EVENT_LOOP_LIB}) + +target_link_directories(${EVENT_LOOP_APP} PUBLIC + ${HEADER_DIR}) \ No newline at end of file diff --git a/test/evloop_app.c b/test/evloop_app.c new file mode 100644 index 0000000..68d3753 --- /dev/null +++ b/test/evloop_app.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +event_loop_t el; +int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + +int +sum(int arr[], int n) { + + int i, sum = 0; + for (i = 0; i < n; i++) { + sum += arr[i]; + } + return sum; +} + +int +mul(int arr[], int n) { + + int i, mul = 1; + for (i = 0; i < n; i++) { + mul *= arr[i]; + } + return mul; +} + +typedef struct arg_obj_ { + + int* arr; + int n; +} arg_obj_t; + + +void +sum_wrapper(void* arg) { + + arg_obj_t* arg_obj = (arg_obj_t*)arg; + printf("sum = %d\n", sum(arg_obj->arr, arg_obj->n)); +} + +void +mul_wrapper(void* arg) { + + arg_obj_t* arg_obj = (arg_obj_t*)arg; + printf("mul = %d\n", mul(arg_obj->arr, arg_obj->n)); +} + + +int +main(int argc, char** argv) { + + event_loop_init(&el); + event_loop_run(&el); + sleep(1); + + arg_obj_t* arg_obj1 = (arg_obj_t*)calloc(1, sizeof(arg_obj_t)); + arg_obj1->arr = arr; + arg_obj1->n = sizeof(arr) / sizeof(arr[0]); + task_t* task_sum = task_create_new_job(&el, sum_wrapper, (void*)arg_obj1); + + + arg_obj_t* arg_obj2 = (arg_obj_t*)calloc(1, sizeof(arg_obj_t)); + arg_obj2->arr = arr; + arg_obj2->n = sizeof(arr) / sizeof(arr[0]); + task_t* task_mul = task_create_new_job(&el, mul_wrapper, (void*)arg_obj2); + + + printf("End of main\n"); + scanf("\n"); +} \ No newline at end of file