diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 6fa30b2b35e8ce53f31a19b08c5ba164efef7ea0..0777e1f3a015ee53cd1caa77709b345e4f4a26b1 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 0000000000000000000000000000000000000000..0b987f1c22563203d55ce901eee2f0fa60002f3c
--- /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 <http://www.gnu.org/licenses/>.
+
+  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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#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 0000000000000000000000000000000000000000..5a3b5eb32732ab0fcc7fe65c58ba9d05f9e3184a
--- /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 <http://www.gnu.org/licenses/>.
+
+  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 <stdint.h>
+#include <pthread.h>
+
+#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_*/