flexran_agent_task_manager.c 8.55 KB
Newer Older
1 2 3 4 5
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * 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.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */ 
21

22 23
/*! \file flexran_agent_task_manager.h
 * \brief Implementation of scheduled tasks manager for the FlexRAN agent
24 25 26 27 28 29 30 31 32 33 34
 * \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>

35 36
#include "flexran_agent_task_manager.h"
#include "flexran_agent_common.c"
37 38 39 40 41 42 43


/* Util macros */
#define LEFT(x) (2 * (x) + 1)
#define RIGHT(x) (2 * (x) + 2)
#define PARENT(x) ((x - 1) / 2)

44 45 46 47
flexran_agent_task_t *flexran_agent_task_create(Protocol__FlexranMessage *msg,
						uint16_t frame_num, uint8_t subframe_num) {
  flexran_agent_task_t *task = NULL;
  task = malloc(sizeof(flexran_agent_task_t));
48 49 50 51 52 53 54 55 56 57 58 59 60 61

  if (task == NULL)
    goto error;

  task->frame_num = frame_num;
  task->subframe_num = subframe_num;
  task->task = msg;
  
  return task;
  
 error:
  return NULL;
}

62
void flexran_agent_task_destroy(flexran_agent_task_t *task) {
63 64 65 66 67 68 69 70
  if (task == NULL)
    return;

  /* TODO: must free the task properly */
  free(task->task);
  free(task);
}

71 72 73 74
flexran_agent_task_queue_t *flexran_agent_task_queue_init(mid_t mod_id, size_t capacity,
							  int (*cmp)(mid_t mod_id, const flexran_agent_task_t *t1,
								     const flexran_agent_task_t *t2)) {
  flexran_agent_task_queue_t *queue = NULL;
75

76
  queue = malloc(sizeof(flexran_agent_task_queue_t));
77 78 79 80 81
  if (queue == NULL)
    goto error;

  /* If no comparator was given, use the default one */
  if (cmp == NULL)
82
    queue->cmp = _flexran_agent_task_queue_cmp;
83 84
  else
    queue->cmp = cmp;
85
  
86 87
  queue->mod_id = mod_id;

88 89 90
  queue->first_frame = 0;
  queue->first_subframe = 0;
  
91
  queue->task = malloc(capacity * sizeof(flexran_agent_task_t *));
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
  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;
}

115 116
flexran_agent_task_queue_t *flexran_agent_task_queue_default_init(mid_t mod_id) {
  return flexran_agent_task_queue_init(mod_id, DEFAULT_CAPACITY, NULL);
117 118
}

119
void flexran_agent_task_queue_destroy(flexran_agent_task_queue_t *queue) {
120 121 122 123 124 125
  int i;
  
  if (queue == NULL)
    return;

  for (i = 0; i < queue->count; i++) {
126
    flexran_agent_task_destroy(queue->task[i]);
127 128 129 130 131 132
  }
  free(queue->task);
  free(queue->mutex);
  free(queue);
}

133
int flexran_agent_task_queue_put(flexran_agent_task_queue_t *queue, flexran_agent_task_t *task) {
134
  size_t i;
135
  flexran_agent_task_t *tmp = NULL;
136 137 138 139 140 141 142 143 144 145
  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*/
146
    realloc_status = _flexran_agent_task_queue_realloc_heap(queue);
147 148 149 150 151 152 153 154 155 156
    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*/
157
  while(i > 0 && queue->cmp(queue->mod_id, queue->task[i], queue->task[PARENT(i)]) > 0) {
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
    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;
}


176
int flexran_agent_task_queue_get_current_task(flexran_agent_task_queue_t *queue, flexran_agent_task_t **task) {
177 178 179 180 181 182 183 184 185 186 187 188 189
  int err_code;
  
  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;
  }
190 191

  /* Find current frame and subframe number */
192 193
  uint16_t curr_frame = flexran_get_current_frame(queue->mod_id);
  uint8_t curr_subframe = flexran_get_current_subframe(queue->mod_id);
194

195 196 197 198 199 200 201 202 203 204
  /* 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 */
205
  _flexran_agent_task_queue_heapify(queue, 0);
206 207 208 209 210 211 212 213 214 215
  
  /*If queue has no element*/
  if (queue->count < 1) {
    queue->first_frame = 0;
    queue->first_subframe = 0;
  } else {
    queue->first_frame = queue->task[0]->frame_num;
    queue->first_subframe = queue->task[0]->subframe_num;
  }
  
216 217 218 219 220 221 222 223 224 225 226 227
  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*/
228
void _flexran_agent_task_queue_heapify(flexran_agent_task_queue_t *queue, size_t idx) {
229
  /* left index, right index, largest */
230
  flexran_agent_task_t *tmp = NULL;
231 232 233 234 235 236
  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 */
237
  if (l_idx < queue->count && queue->cmp(queue->mod_id, queue->task[l_idx], queue->task[idx]) > 0) {
238 239 240 241 242 243
    lrg_idx = l_idx;
  } else {
    lrg_idx = idx;
  }

  /* Right child exists, compare right child with the largest element */
244
  if (r_idx < queue->count && queue->cmp(queue->mod_id, queue->task[r_idx], queue->task[lrg_idx]) > 0) {
245 246 247 248 249 250 251 252 253 254
    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 */
255
    _flexran_agent_task_queue_heapify(queue, lrg_idx);
256 257 258 259
  }
}

/*Warning: Internal function. Should not be called as API function. Not thread safe*/
260 261
int _flexran_agent_task_queue_realloc_heap(flexran_agent_task_queue_t *queue) {
  flexran_agent_task_t **resized_task_heap;
262
  if (queue->count >= queue->capacity) {
263
    size_t task_size = sizeof(flexran_agent_task_t);
264 265 266 267

    resized_task_heap = realloc(queue->task, (2*queue->capacity) * task_size);
    if (resized_task_heap != NULL) {
      queue->capacity *= 2;
268
      queue->task = (flexran_agent_task_t **) resized_task_heap;
269 270 271 272 273 274
      return HEAP_OK;
    } else return HEAP_REALLOCERROR;
  }
  return HEAP_NOREALLOC;
}

275
int _flexran_agent_task_queue_cmp(mid_t mod_id, const flexran_agent_task_t *t1, const flexran_agent_task_t *t2) {
276 277
  if ((t1->frame_num == t2->frame_num) && (t1->subframe_num == t2->subframe_num))
    return 0;
278

279 280
  uint16_t curr_frame = flexran_get_current_frame(mod_id);
  uint8_t curr_subframe = flexran_get_current_subframe(mod_id);
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304

  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;
}