mirror of
https://github.com/Hizenberg469/Event-Loop-in-C.git
synced 2026-04-19 16:52:24 +03:00
Skeleton Event Loop Ready
This commit is contained in:
@@ -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)
|
||||||
@@ -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
|
||||||
@@ -4,4 +4,16 @@ add_library(${EVENT_LOOP_LIB} STATIC
|
|||||||
${EVENT_LOOP_SRC})
|
${EVENT_LOOP_SRC})
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
179
src/event_loop.c
179
src/event_loop.c
@@ -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
11
test/CMakeLists.txt
Normal 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
72
test/evloop_app.c
Normal 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");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user