/* * 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 * the OAI Public License, Version 1.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.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 */ /*! \file flexran_agent_task_manager.h * \brief Implementation of scheduled tasks manager for the FlexRAN agent * \author Xenofon Foukas * \date January 2016 * \version 0.1 * \email: x.foukas@sms.ed.ac.uk * @ingroup _mac */ #include #include #include #include "flexran_agent_task_manager.h" #include "flexran_agent_common.c" /* Util macros */ #define LEFT(x) (2 * (x) + 1) #define RIGHT(x) (2 * (x) + 2) #define PARENT(x) ((x - 1) / 2) 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)); if (task == NULL) goto error; task->frame_num = frame_num; task->subframe_num = subframe_num; task->task = msg; return task; error: return NULL; } void flexran_agent_task_destroy(flexran_agent_task_t *task) { if (task == NULL) return; /* TODO: must free the task properly */ free(task->task); free(task); } 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; queue = malloc(sizeof(flexran_agent_task_queue_t)); if (queue == NULL) goto error; /* If no comparator was given, use the default one */ if (cmp == NULL) queue->cmp = _flexran_agent_task_queue_cmp; else queue->cmp = cmp; queue->mod_id = mod_id; queue->first_frame = 0; queue->first_subframe = 0; queue->task = malloc(capacity * sizeof(flexran_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; } 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); } void flexran_agent_task_queue_destroy(flexran_agent_task_queue_t *queue) { int i; if (queue == NULL) return; for (i = 0; i < queue->count; i++) { flexran_agent_task_destroy(queue->task[i]); } free(queue->task); free(queue->mutex); free(queue); } int flexran_agent_task_queue_put(flexran_agent_task_queue_t *queue, flexran_agent_task_t *task) { size_t i; flexran_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 = _flexran_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->mod_id, 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 flexran_agent_task_queue_get_current_task(flexran_agent_task_queue_t *queue, flexran_agent_task_t **task) { 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; } /* Find current frame and subframe number */ uint16_t curr_frame = flexran_get_current_frame(queue->mod_id); uint8_t curr_subframe = flexran_get_current_subframe(queue->mod_id); /* 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 */ _flexran_agent_task_queue_heapify(queue, 0); /*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; } 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 _flexran_agent_task_queue_heapify(flexran_agent_task_queue_t *queue, size_t idx) { /* left index, right index, largest */ flexran_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->mod_id, 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->mod_id, 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 */ _flexran_agent_task_queue_heapify(queue, lrg_idx); } } /*Warning: Internal function. Should not be called as API function. Not thread safe*/ int _flexran_agent_task_queue_realloc_heap(flexran_agent_task_queue_t *queue) { flexran_agent_task_t **resized_task_heap; if (queue->count >= queue->capacity) { size_t task_size = sizeof(flexran_agent_task_t); resized_task_heap = realloc(queue->task, (2*queue->capacity) * task_size); if (resized_task_heap != NULL) { queue->capacity *= 2; queue->task = (flexran_agent_task_t **) resized_task_heap; return HEAP_OK; } else return HEAP_REALLOCERROR; } return HEAP_NOREALLOC; } int _flexran_agent_task_queue_cmp(mid_t mod_id, const flexran_agent_task_t *t1, const flexran_agent_task_t *t2) { if ((t1->frame_num == t2->frame_num) && (t1->subframe_num == t2->subframe_num)) return 0; uint16_t curr_frame = flexran_get_current_frame(mod_id); uint8_t curr_subframe = flexran_get_current_subframe(mod_id); 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; }