Skeleton Event Loop Ready

This commit is contained in:
2024-06-03 16:03:05 +05:30
parent c4c3b013c0
commit 6114206eb7
6 changed files with 289 additions and 4 deletions

View File

@@ -34,4 +34,4 @@ set(SOURCE_DIR ${CMAKE_SOURCE_DIR}/src)
#Adding Sub-directory having CMakeLists.txt... #Adding Sub-directory having CMakeLists.txt...
add_subdirectory(src) add_subdirectory(src)
#add_subdirectory(test) add_subdirectory(test)

View File

@@ -1,11 +1,13 @@
#ifndef __EV_LOOP__ #ifndef __EV_LOOP__
#define __EV_LOOP__ #define __EV_LOOP__
#include <pthread.h>
typedef struct task_ task_t; typedef struct task_ task_t;
typedef struct event_loop_ event_loop_t; typedef struct event_loop_ event_loop_t;
typedef EL_RES_T(*event_cbk)(void*); typedef void (*event_cbk)(void*);
struct task_ { struct task_ {
@@ -23,7 +25,7 @@ typedef enum {
struct event_loop_ { struct event_loop_ {
/* head to the start of the task array */ /* 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 /* Mutex to enforce Mutual exclusion enqueue/Deque
* Operation in task array. Also used to update event loop * Operation in task array. Also used to update event loop
* attributes in mutual exclusive way * attributes in mutual exclusive way
@@ -40,4 +42,13 @@ struct event_loop_ {
struct task_* current_task; 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 #endif

View File

@@ -5,3 +5,15 @@ add_library(${EVENT_LOOP_LIB} STATIC
target_include_directories(${EVENT_LOOP_LIB} PUBLIC target_include_directories(${EVENT_LOOP_LIB} PUBLIC
${HEADER_DIR}) ${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)

View File

@@ -0,0 +1,179 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <unistd.h>
#include <event_loop.h>
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);
}

11
test/CMakeLists.txt Normal file
View File

@@ -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})

72
test/evloop_app.c Normal file
View File

@@ -0,0 +1,72 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <event_loop.h>
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");
}