aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-light/src/hicn/base/loop.c
diff options
context:
space:
mode:
Diffstat (limited to 'hicn-light/src/hicn/base/loop.c')
-rw-r--r--hicn-light/src/hicn/base/loop.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/hicn-light/src/hicn/base/loop.c b/hicn-light/src/hicn/base/loop.c
new file mode 100644
index 000000000..3407bfc1c
--- /dev/null
+++ b/hicn-light/src/hicn/base/loop.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file loop.c
+ * @brief Implementation of event loop based on libevent
+ */
+
+#include <assert.h>
+#include <event2/event.h>
+#include <event2/event_struct.h>
+#include <event2/thread.h>
+#include <fcntl.h> // fcntl
+#ifdef WITH_THREAD
+#include <pthread.h>
+#endif /* WITH_THREAD */
+#include <hicn/util/log.h>
+#include <stdlib.h>
+#include <unistd.h> // fcntl
+
+#include "loop.h"
+
+loop_t *MAIN_LOOP = NULL;
+
+/**
+ * \brief Holds all callback parameters
+ */
+typedef struct {
+ void *owner;
+ fd_callback_t callback;
+ unsigned id;
+ void *data;
+} cb_wrapper_args_t;
+
+typedef enum {
+ EVTYPE_TIMER,
+ EVTYPE_FD,
+} event_type_t;
+
+struct loop_s {
+ /* Libevent-based implementation */
+ struct event_base *event_base;
+};
+
+struct event_s {
+ /* Reference to loop */
+ loop_t *loop;
+
+ /* Event type*/
+ event_type_t event_type;
+
+ /* Raw event */
+ struct event raw_event;
+
+ /* Callback on event */
+ cb_wrapper_args_t callback;
+};
+
+loop_t *loop_create() {
+ loop_t *loop = malloc(sizeof(loop_t));
+
+ if (!loop) {
+ ERROR("[loop_create] Failed to allocate memory");
+ goto ERR_MALLOC;
+ }
+
+#ifdef WITH_THREAD
+ evthread_use_pthreads();
+#endif /* WITH_THREAD */
+
+ loop->event_base = event_base_new();
+ if (!loop->event_base) goto ERR_EVENT;
+
+ event_set_log_callback(NULL);
+
+ return loop;
+
+ERR_EVENT:
+ERR_MALLOC:
+ return NULL;
+}
+
+void loop_free(loop_t *loop) {
+ event_base_free(loop->event_base);
+ free(loop);
+}
+
+int _loop_dispatch(loop_t *loop, int flags) {
+ event_base_loop(loop->event_base, flags);
+ return 0;
+}
+
+int loop_dispatch(loop_t *loop) {
+ return _loop_dispatch(loop, EVLOOP_NO_EXIT_ON_EMPTY);
+}
+
+int loop_break(loop_t *loop) { return event_base_loopbreak(loop->event_base); }
+
+int loop_undispatch(loop_t *loop) { return 0; }
+
+void cb_wrapper(evutil_socket_t fd, short what, void *arg) {
+ cb_wrapper_args_t *cb_wrapper_args = arg;
+ cb_wrapper_args->callback(cb_wrapper_args->owner, fd, cb_wrapper_args->id,
+ cb_wrapper_args->data);
+}
+
+static inline void _event_create(event_t **event, loop_t *loop,
+ event_type_t type, void *callback_owner,
+ fd_callback_t callback, unsigned id,
+ void *callback_data) {
+ *event = malloc(sizeof(event_t));
+ (*event)->callback = (cb_wrapper_args_t){
+ .owner = callback_owner,
+ .callback = callback,
+ .id = id,
+ .data = callback_data,
+ };
+ (*event)->event_type = type;
+ (*event)->loop = loop;
+}
+
+int loop_fd_event_create(event_t **event, loop_t *loop, int fd,
+ void *callback_owner, fd_callback_t callback,
+ unsigned id, void *callback_data) {
+ _event_create(event, loop, EVTYPE_FD, callback_owner, callback, id,
+ callback_data);
+
+ evutil_make_socket_nonblocking(fd);
+ event_assign(&(*event)->raw_event, loop->event_base, fd, EV_READ | EV_PERSIST,
+ cb_wrapper, &(*event)->callback);
+
+ return 0;
+}
+
+int loop_fd_event_register(event_t *event) {
+ assert(event->event_type == EVTYPE_FD);
+
+ if (event_add(&event->raw_event, NULL) < 0) {
+ ERROR("[loop_fd_event_register] event_add");
+ goto ERR_EVENT_ADD;
+ }
+
+ return 0;
+
+ERR_EVENT_ADD:
+ return -1;
+}
+
+int loop_event_unregister(event_t *event) {
+ event_del(&event->raw_event);
+ return 0;
+}
+
+int loop_timer_create(event_t **timer, loop_t *loop, void *callback_owner,
+ fd_callback_t callback, void *callback_data) {
+ _event_create(timer, loop, EVTYPE_TIMER, callback_owner, callback, 0,
+ callback_data);
+
+ evtimer_assign(&(*timer)->raw_event, loop->event_base, cb_wrapper,
+ &(*timer)->callback);
+
+ return 0;
+}
+
+static inline void _ms_to_timeval(unsigned delay_ms, struct timeval *tv) {
+ tv->tv_sec = delay_ms / 1000;
+ tv->tv_usec = (delay_ms % 1000) * 1000;
+}
+
+int loop_timer_register(event_t *timer, unsigned delay_ms) {
+ assert(timer->event_type == EVTYPE_TIMER);
+
+ struct timeval tv;
+ _ms_to_timeval(delay_ms, &tv);
+
+ if (tv.tv_sec == 0 && tv.tv_usec == 0) {
+ event_active(&timer->raw_event, EV_TIMEOUT, 0);
+ } else {
+ event_add(&timer->raw_event, &tv);
+ }
+
+ return 0;
+}
+
+int loop_timer_is_enabled(event_t *timer) {
+ return evtimer_pending(&timer->raw_event, NULL) != 0;
+}
+
+int loop_event_free(event_t *event) {
+ int ret = loop_event_unregister(event);
+ free(event);
+ return ret;
+}