diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 6fa30b2b35..0777e1f3a0 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -746,6 +746,7 @@ if (ENB_AGENT_SB_IF)
${OPENAIR2_DIR}/ENB_APP/enb_agent_common.c
${OPENAIR2_DIR}/ENB_APP/enb_agent_mac.c
${OPENAIR2_DIR}/ENB_APP/enb_agent.c
+ ${OPENAIR2_DIR}/ENB_APP/enb_agent_task_manager.c
)
set(ENB_AGENT_LIB ENB_AGENT)
#include_directories(${OPENAIR2_DIR}/ENB_APP)
diff --git a/openair2/ENB_APP/enb_agent_task_manager.c b/openair2/ENB_APP/enb_agent_task_manager.c
new file mode 100644
index 0000000000..0b987f1c22
--- /dev/null
+++ b/openair2/ENB_APP/enb_agent_task_manager.c
@@ -0,0 +1,303 @@
+/*******************************************************************************
+ OpenAirInterface
+ Copyright(c) 1999 - 2015 Eurecom
+
+ OpenAirInterface 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, either version 3 of the License, or
+ (at your option) any later version.
+
+
+ OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
+ included in this distribution in the file called "COPYING". If not,
+ see .
+
+ Contact Information
+ OpenAirInterface Admin: openair_admin@eurecom.fr
+ OpenAirInterface Tech : openair_tech@eurecom.fr
+ OpenAirInterface Dev : openair4g-devel@eurecom.fr
+
+ Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
+
+*******************************************************************************/
+/*! \file enb_agent_task_manager.h
+ * \brief Implementation of scheduled tasks manager for the enb agent
+ * \author Xenofon Foukas
+ * \date January 2016
+ * \version 0.1
+ * \email: x.foukas@sms.ed.ac.uk
+ * @ingroup _mac
+ */
+
+#include
+#include
+#include
+
+#include "enb_agent_task_manager.h"
+
+
+/* Util macros */
+#define LEFT(x) (2 * (x) + 1)
+#define RIGHT(x) (2 * (x) + 2)
+#define PARENT(x) ((x - 1) / 2)
+
+enb_agent_task_t *enb_agent_task_create(Protocol__ProgranMessage *msg,
+ uint16_t frame_num, uint8_t subframe_num) {
+ enb_agent_task_t *task = NULL;
+ task = malloc(sizeof(enb_agent_task_t));
+
+ if (task == NULL)
+ goto error;
+
+ task->frame_num = frame_num;
+ task->subframe_num = subframe_num;
+ task->task = msg;
+
+ return task;
+
+ error:
+ return NULL;
+}
+
+void enb_agent_task_destroy(enb_agent_task_t *task) {
+ if (task == NULL)
+ return;
+
+ /* TODO: must free the task properly */
+ free(task->task);
+ free(task);
+}
+
+enb_agent_task_queue_t *enb_agent_task_queue_init(size_t capacity,
+ int (*cmp)(const enb_agent_task_t *t1, const enb_agent_task_t *t2)) {
+ enb_agent_task_queue_t *queue = NULL;
+
+ queue = malloc(sizeof(enb_agent_task_queue_t));
+ if (queue == NULL)
+ goto error;
+
+ /* If no comparator was given, use the default one */
+ if (cmp == NULL)
+ queue->cmp = _enb_agent_task_queue_cmp;
+ else
+ queue->cmp = cmp;
+
+ queue->first_frame = 0;
+ queue->first_subframe = 0;
+
+ queue->task = malloc(capacity * sizeof(enb_agent_task_t *));
+ if (queue->task == NULL)
+ goto error;
+
+ queue->count = 0;
+ queue->capacity = capacity;
+
+ queue->mutex = malloc(sizeof(pthread_mutex_t));
+ if (queue->mutex == NULL)
+ goto error;
+ if (pthread_mutex_init(queue->mutex, NULL))
+ goto error;
+
+ return queue;
+
+ error:
+ if (queue != NULL) {
+ free(queue->mutex);
+ free(queue->task);
+ free(queue);
+ }
+ return NULL;
+}
+
+enb_agent_task_queue_t *enb_agent_task_queue_default_init() {
+ return enb_agent_task_queue_init(DEFAULT_CAPACITY, NULL);
+}
+
+void enb_agent_task_queue_destroy(enb_agent_task_queue_t *queue) {
+ int i;
+
+ if (queue == NULL)
+ return;
+
+ for (i = 0; i < queue->count; i++) {
+ enb_agent_task_destroy(queue->task[i]);
+ }
+ free(queue->task);
+ free(queue->mutex);
+ free(queue);
+}
+
+int enb_agent_task_queue_put(enb_agent_task_queue_t *queue, enb_agent_task_t *task) {
+ size_t i;
+ enb_agent_task_t *tmp = NULL;
+ int realloc_status, err_code;
+
+ if (pthread_mutex_lock(queue->mutex)) {
+ /*TODO*/
+ err_code = -1;
+ goto error;
+ }
+
+ if (queue->count >= queue->capacity) {
+ /*TODO: need to call realloc heap*/
+ realloc_status = _enb_agent_task_queue_realloc_heap(queue);
+ if (realloc_status != HEAP_OK) {
+ err_code = realloc_status;
+ goto error;
+ }
+ }
+
+ queue->task[queue->count] = task;
+ i = queue->count;
+ queue->count++;
+ /*Swap elements to maintain heap properties*/
+ while(i > 0 && queue->cmp(queue->task[i], queue->task[PARENT(i)]) > 0) {
+ tmp = queue->task[i];
+ queue->task[i] = queue->task[PARENT(i)];
+ queue->task[PARENT(i)] = tmp;
+ i = PARENT(i);
+ }
+
+ if (pthread_mutex_unlock(queue->mutex)) {
+ // LOG_E(MAC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__);
+ exit(1);
+ }
+ return 0;
+
+ error:
+ /*TODO*/
+ return err_code;
+}
+
+
+int enb_agent_task_queue_get_current_task(enb_agent_task_queue_t *queue, enb_agent_task_t **task) {
+ int err_code;
+
+ /*TODO*/
+ /* Find current frame and subframe number */
+ uint16_t curr_frame=1;
+ uint8_t curr_subframe=1;
+
+ if (pthread_mutex_lock(queue->mutex)) {
+ /*TODO*/
+ err_code = -1;
+ goto error;
+ }
+
+ if (queue->count < 1) {
+ /* Priority Queue is empty */
+ err_code = HEAP_EMPTY;
+ goto error;
+ }
+ /* If no task is scheduled for the current subframe, return without any task */
+ if(queue->task[0]->frame_num != curr_frame || queue->task[0]->subframe_num != curr_subframe) {
+ *task = NULL;
+ return 0;
+ }
+ /* Otherwise, the first task should be returned */
+ *task = queue->task[0];
+ queue->task[0] = queue->task[queue->count-1];
+ queue->count--;
+ /* Restore heap property */
+ _enb_agent_task_queue_heapify(queue, 0);
+
+ if (pthread_mutex_unlock(queue->mutex)) {
+ // LOG_E(MAC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__);
+ exit(1);
+ }
+ return HEAP_OK;
+
+ error:
+ /*TODO*/
+ return err_code;
+}
+
+/*Warning: Internal function. Should not be called as API function. Not thread safe*/
+void _enb_agent_task_queue_heapify(enb_agent_task_queue_t *queue, size_t idx) {
+ /* left index, right index, largest */
+ enb_agent_task_t *tmp = NULL;
+ size_t l_idx, r_idx, lrg_idx;
+
+ l_idx = LEFT(idx);
+ r_idx = RIGHT(idx);
+
+ /* Left child exists, compare left child with its parent */
+ if (l_idx < queue->count && queue->cmp(queue->task[l_idx], queue->task[idx]) > 0) {
+ lrg_idx = l_idx;
+ } else {
+ lrg_idx = idx;
+ }
+
+ /* Right child exists, compare right child with the largest element */
+ if (r_idx < queue->count && queue->cmp(queue->task[r_idx], queue->task[lrg_idx]) > 0) {
+ lrg_idx = r_idx;
+ }
+
+ /* At this point largest element was determined */
+ if (lrg_idx != idx) {
+ /* Swap between the index at the largest element */
+ tmp = queue->task[lrg_idx];
+ queue->task[lrg_idx] = queue->task[idx];
+ queue->task[idx] = tmp;
+ /* Heapify again */
+ _enb_agent_task_queue_heapify(queue, lrg_idx);
+ }
+}
+
+/*Warning: Internal function. Should not be called as API function. Not thread safe*/
+int _enb_agent_task_queue_realloc_heap(enb_agent_task_queue_t *queue) {
+ enb_agent_task_t **resized_task_heap;
+ if (queue->count >= queue->capacity) {
+ size_t task_size = sizeof(enb_agent_task_t);
+
+ resized_task_heap = realloc(queue->task, (2*queue->capacity) * task_size);
+ if (resized_task_heap != NULL) {
+ queue->capacity *= 2;
+ queue->task = (enb_agent_task_t **) resized_task_heap;
+ return HEAP_OK;
+ } else return HEAP_REALLOCERROR;
+ }
+ return HEAP_NOREALLOC;
+}
+
+int _enb_agent_task_queue_cmp(const enb_agent_task_t *t1, const enb_agent_task_t *t2) {
+ if ((t1->frame_num == t2->frame_num) && (t1->subframe_num == t2->subframe_num))
+ return 0;
+ /* TODO: need to get current frame and subframe number */
+ uint16_t curr_frame = 0;
+ uint8_t curr_subframe = 7;
+
+ int f_offset, sf_offset, tmp1, tmp2;
+
+ /*Check if the offsets have the same sign and compare the tasks position frame-wise*/
+ tmp1 = t1->frame_num - curr_frame;
+ tmp2 = t2->frame_num - curr_frame;
+ if ((tmp1 >= 0) ^ (tmp2 < 0)) {
+ f_offset = tmp2 - tmp1;
+ }
+ else {
+ f_offset = tmp1 - tmp2;
+ }
+ /*Do the same for the subframe*/
+ tmp1 = t1->subframe_num - curr_subframe;
+ tmp2 = t2->subframe_num - curr_subframe;
+ if ((tmp1 >= 0) ^ (tmp2 < 0))
+ sf_offset = tmp2 - tmp1;
+ else
+ sf_offset = tmp1 - tmp2;
+
+ /*Subframe position matters only if f_offset is 0. Multiply f_offset by 100
+ to be the only comparisson parameter in all other cases */
+ return f_offset*100 + sf_offset;
+}
+
+
+int main(int argc, char **argv) {
+ return 0;
+}
diff --git a/openair2/ENB_APP/enb_agent_task_manager.h b/openair2/ENB_APP/enb_agent_task_manager.h
new file mode 100644
index 0000000000..5a3b5eb327
--- /dev/null
+++ b/openair2/ENB_APP/enb_agent_task_manager.h
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ OpenAirInterface
+ Copyright(c) 1999 - 2015 Eurecom
+
+ OpenAirInterface 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, either version 3 of the License, or
+ (at your option) any later version.
+
+
+ OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
+ included in this distribution in the file called "COPYING". If not,
+ see .
+
+ Contact Information
+ OpenAirInterface Admin: openair_admin@eurecom.fr
+ OpenAirInterface Tech : openair_tech@eurecom.fr
+ OpenAirInterface Dev : openair4g-devel@eurecom.fr
+
+ Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
+
+*******************************************************************************/
+/*! \file enb_agent_task_manager.h
+ * \brief Implementation of scheduled tasks manager for the enb agent
+ * \author Xenofon Foukas
+ * \date January 2016
+ * \version 0.1
+ * \email: x.foukas@sms.ed.ac.uk
+ * @ingroup _mac
+ */
+
+#ifndef ENB_AGENT_TASK_MANAGER_
+#define ENB_AGENT_TASK_MANAGER_
+
+#include
+#include
+
+#include "progran.pb-c.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DEFAULT_CAPACITY 512
+
+/**
+ * The structure containing the enb agent task to be executed
+ */
+typedef struct enb_agent_task_s {
+ /* The frame in which the task needs to be executed */
+ uint16_t frame_num;
+ /* The subframe in which the task needs to be executed */
+ uint8_t subframe_num;
+ /* The task to be executed in the form of a Protocol__ProgranMessage */
+ Protocol__ProgranMessage *task;
+} enb_agent_task_t;
+
+/**
+ * Priority Queue Structure for tasks
+ */
+typedef struct enb_agent_task_queue_s {
+ /* The amount of allocated memory for agent tasks in the heap*/
+ volatile size_t capacity;
+ /* The actual size of the tasks heap at a certain time */
+ volatile size_t count;
+ /* The earliest frame that has a pending task */
+ volatile uint16_t first_frame;
+ /* The earliest subframe within the frame that has a pending task */
+ volatile uint8_t first_subframe;
+ /* An array of prioritized tasks stored in a heap */
+ enb_agent_task_t **task;
+ /* A pointer to a comparator function, used to prioritize elements */
+ int (*cmp)(const enb_agent_task_t *t1, const enb_agent_task_t *t2);
+ pthread_mutex_t *mutex;
+} enb_agent_task_queue_t;
+
+typedef enum {
+ HEAP_OK = 0,
+ HEAP_EMPTY,
+ HEAP_FAILED,
+ HEAP_REALLOCERROR,
+ HEAP_NOREALLOC,
+ HEAP_FATAL,
+} heapstatus_e;
+
+/**
+ * Allocate memory for a task in the queue
+ */
+enb_agent_task_t *enb_agent_task_create(Protocol__ProgranMessage *msg,
+ uint16_t frame_num, uint8_t subframe_num);
+
+/**
+ * Free memory for a task of the queue
+ */
+void enb_agent_task_destroy(enb_agent_task_t *task);
+
+/**
+ * Allocate initial memory for storing the tasks
+ */
+enb_agent_task_queue_t *enb_agent_task_queue_init(size_t capacity,
+ int (*cmp)(const enb_agent_task_t *t1, const enb_agent_task_t *t2));
+
+/**
+ * Allocate initial memory for storing the tasks using default parameters
+ */
+enb_agent_task_queue_t *enb_agent_task_queue_default_init();
+
+/**
+ * De-allocate memory for the tasks queue
+ */
+void enb_agent_task_queue_destroy(enb_agent_task_queue_t *queue);
+
+/**
+ * Insert task into the queue
+ */
+int enb_agent_task_queue_put(enb_agent_task_queue_t *queue, enb_agent_task_t *task);
+
+/**
+ * Remove the task with the highest priority from the queue
+ * task becomes NULL if there is no task for the current frame and subframe
+ */
+int enb_agent_task_queue_get_current_task(enb_agent_task_queue_t *queue, enb_agent_task_t **task);
+
+/**
+ * Check if the top priority task is for a specific frame and subframe
+ */
+int enb_agent_task_queue_has_upcoming_task (enb_agent_task_queue_t *queue,
+ const uint16_t frame, const uint8_t subframe);
+
+/**
+ * Restructure heap after modifications
+ */
+void _enb_agent_task_queue_heapify(enb_agent_task_queue_t *queue, size_t idx);
+
+/**
+ * Reallocate memory once the heap reaches max size
+ */
+int _enb_agent_task_queue_realloc_heap(enb_agent_task_queue_t *queue);
+
+/**
+ * Compare two agent tasks based on frame and subframe
+ * returns 0 if tasks t1, t2 have the same priority
+ * return negative value if t1 needs to be executed after t2
+ * return positive value if t1 preceeds t2
+ */
+int _enb_agent_task_queue_cmp(const enb_agent_task_t *t1, const enb_agent_task_t *t2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*ENB_AGENT_TASK_MANAGER_*/