| /****************************************************************************** |
| * |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * 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. |
| * |
| ***************************************************************************** |
| * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore |
| */ |
| /** |
| ******************************************************************************* |
| * @file |
| * ih264_list.c |
| * |
| * @brief |
| * Contains functions for buf queue |
| * |
| * @author |
| * Harish |
| * |
| * @par List of Functions: |
| * ih264_list_size() |
| * ih264_list_lock() |
| * ih264_list_unlock() |
| * ih264_list_yield() |
| * ih264_list_free() |
| * ih264_list_init() |
| * ih264_list_reset() |
| * ih264_list_deinit() |
| * ih264_list_terminate() |
| * ih264_list_queue() |
| * ih264_list_dequeue() |
| * |
| * @remarks |
| * None |
| * |
| ******************************************************************************* |
| */ |
| /*****************************************************************************/ |
| /* File Includes */ |
| /*****************************************************************************/ |
| #include <stdio.h> |
| #include <stddef.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <assert.h> |
| |
| #include "ih264_typedefs.h" |
| #include "ithread.h" |
| #include "ih264_platform_macros.h" |
| #include "ih264_macros.h" |
| #include "ih264_debug.h" |
| #include "ih264_error.h" |
| #include "ih264_list.h" |
| |
| /** |
| ******************************************************************************* |
| * |
| * @brief Returns size for buf queue context. Does not include buf queue buffer |
| * requirements |
| * |
| * @par Description |
| * Returns size for buf queue context. Does not include buf queue buffer |
| * requirements. Buffer size required to store the bufs should be allocated in |
| * addition to the value returned here. |
| * |
| * @returns Size of the buf queue context |
| * |
| * @remarks |
| * |
| ******************************************************************************* |
| */ |
| WORD32 ih264_list_size(WORD32 num_entries, WORD32 entry_size) |
| { |
| WORD32 size; |
| WORD32 clz; |
| size = sizeof(list_t); |
| size += ithread_get_mutex_lock_size(); |
| |
| /* Use next power of two number of entries*/ |
| clz = CLZ(num_entries); |
| num_entries = 1 << (32 - clz); |
| |
| size += num_entries * entry_size; |
| return size; |
| } |
| |
| /** |
| ******************************************************************************* |
| * |
| * @brief |
| * Locks the list context |
| * |
| * @par Description |
| * Locks the list context by calling ithread_mutex_lock() |
| * |
| * @param[in] ps_list |
| * Job Queue context |
| * |
| * @returns IH264_FAIL if mutex lock fails else IH264_SUCCESS |
| * |
| * @remarks |
| * |
| ******************************************************************************* |
| */ |
| IH264_ERROR_T ih264_list_lock(list_t *ps_list) |
| { |
| WORD32 retval; |
| retval = ithread_mutex_lock(ps_list->pv_mutex); |
| if(retval) |
| { |
| return IH264_FAIL; |
| } |
| return IH264_SUCCESS; |
| } |
| |
| /** |
| ******************************************************************************* |
| * |
| * @brief |
| * Unlocks the list context |
| * |
| * @par Description |
| * Unlocks the list context by calling ithread_mutex_unlock() |
| * |
| * @param[in] ps_list |
| * Job Queue context |
| * |
| * @returns IH264_FAIL if mutex unlock fails else IH264_SUCCESS |
| * |
| * @remarks |
| * |
| ******************************************************************************* |
| */ |
| |
| IH264_ERROR_T ih264_list_unlock(list_t *ps_list) |
| { |
| WORD32 retval; |
| retval = ithread_mutex_unlock(ps_list->pv_mutex); |
| if(retval) |
| { |
| return IH264_FAIL; |
| } |
| return IH264_SUCCESS; |
| |
| } |
| /** |
| ******************************************************************************* |
| * |
| * @brief |
| * Yields the thread |
| * |
| * @par Description |
| * Unlocks the list context by calling |
| * ih264_list_unlock(), ithread_yield() and then ih264_list_lock() |
| * list is unlocked before to ensure the list can be accessed by other threads |
| * If unlock is not done before calling yield then no other thread can access |
| * the list functions and update list. |
| * |
| * @param[in] ps_list |
| * Job Queue context |
| * |
| * @returns IH264_FAIL if mutex lock unlock or yield fails else IH264_SUCCESS |
| * |
| * @remarks |
| * |
| ******************************************************************************* |
| */ |
| IH264_ERROR_T ih264_list_yield(list_t *ps_list) |
| { |
| |
| IH264_ERROR_T ret = IH264_SUCCESS; |
| |
| IH264_ERROR_T rettmp; |
| rettmp = ih264_list_unlock(ps_list); |
| RETURN_IF((rettmp != IH264_SUCCESS), rettmp); |
| |
| ithread_yield(); |
| |
| if(ps_list->i4_yeild_interval_us > 0) |
| ithread_usleep(ps_list->i4_yeild_interval_us); |
| |
| rettmp = ih264_list_lock(ps_list); |
| RETURN_IF((rettmp != IH264_SUCCESS), rettmp); |
| return ret; |
| } |
| |
| |
| /** |
| ******************************************************************************* |
| * |
| * @brief free the buf queue pointers |
| * |
| * @par Description |
| * Frees the list context |
| * |
| * @param[in] pv_buf |
| * Memory for buf queue buffer and buf queue context |
| * |
| * @returns Pointer to buf queue context |
| * |
| * @remarks |
| * Since it will be called only once by master thread this is not thread safe. |
| * |
| ******************************************************************************* |
| */ |
| IH264_ERROR_T ih264_list_free(list_t *ps_list) |
| { |
| WORD32 ret; |
| ret = ithread_mutex_destroy(ps_list->pv_mutex); |
| |
| if(0 == ret) |
| return IH264_SUCCESS; |
| else |
| return IH264_FAIL; |
| } |
| |
| /** |
| ******************************************************************************* |
| * |
| * @brief Initialize the buf queue |
| * |
| * @par Description |
| * Initializes the list context and sets write and read pointers to start of |
| * buf queue buffer |
| * |
| * @param[in] pv_buf |
| * Memoy for buf queue buffer and buf queue context |
| * |
| * @param[in] buf_size |
| * Size of the total memory allocated |
| * |
| * @returns Pointer to buf queue context |
| * |
| * @remarks |
| * Since it will be called only once by master thread this is not thread safe. |
| * |
| ******************************************************************************* |
| */ |
| void* ih264_list_init(void *pv_buf, |
| WORD32 buf_size, |
| WORD32 num_entries, |
| WORD32 entry_size, |
| WORD32 yeild_interval_us) |
| { |
| list_t *ps_list; |
| UWORD8 *pu1_buf; |
| |
| pu1_buf = (UWORD8 *)pv_buf; |
| |
| ps_list = (list_t *)pu1_buf; |
| pu1_buf += sizeof(list_t); |
| buf_size -= sizeof(list_t); |
| |
| ps_list->pv_mutex = pu1_buf; |
| pu1_buf += ithread_get_mutex_lock_size(); |
| buf_size -= ithread_get_mutex_lock_size(); |
| |
| if (buf_size <= 0) |
| return NULL; |
| |
| ithread_mutex_init(ps_list->pv_mutex); |
| |
| /* Ensure num_entries is power of two */ |
| ASSERT(0 == (num_entries & (num_entries - 1))); |
| |
| /* Ensure remaining buffer is large enough to hold given number of entries */ |
| ASSERT((num_entries * entry_size) <= buf_size); |
| |
| ps_list->pv_buf_base = pu1_buf; |
| ps_list->i4_terminate = 0; |
| ps_list->i4_entry_size = entry_size; |
| ps_list->i4_buf_rd_idx = 0; |
| ps_list->i4_buf_wr_idx = 0; |
| ps_list->i4_log2_buf_max_idx = 32 - CLZ(num_entries); |
| ps_list->i4_buf_max_idx = num_entries; |
| ps_list->i4_yeild_interval_us = yeild_interval_us; |
| |
| return ps_list; |
| } |
| /** |
| ******************************************************************************* |
| * |
| * @brief |
| * Resets the list context |
| * |
| * @par Description |
| * Resets the list context by initializing buf queue context elements |
| * |
| * @param[in] ps_list |
| * Job Queue context |
| * |
| * @returns IH264_FAIL if lock unlock fails else IH264_SUCCESS |
| * |
| * @remarks |
| * |
| ******************************************************************************* |
| */ |
| IH264_ERROR_T ih264_list_reset(list_t *ps_list) |
| { |
| IH264_ERROR_T ret = IH264_SUCCESS; |
| ret = ih264_list_lock(ps_list); |
| RETURN_IF((ret != IH264_SUCCESS), ret); |
| |
| ps_list->i4_terminate = 0; |
| ps_list->i4_buf_rd_idx = 0; |
| ps_list->i4_buf_wr_idx = 0; |
| |
| ret = ih264_list_unlock(ps_list); |
| RETURN_IF((ret != IH264_SUCCESS), ret); |
| |
| return ret; |
| } |
| |
| /** |
| ******************************************************************************* |
| * |
| * @brief |
| * Deinitializes the list context |
| * |
| * @par Description |
| * Deinitializes the list context by calling ih264_list_reset() |
| * and then destrying the mutex created |
| * |
| * @param[in] ps_list |
| * Job Queue context |
| * |
| * @returns IH264_FAIL if lock unlock fails else IH264_SUCCESS |
| * |
| * @remarks |
| * |
| ******************************************************************************* |
| */ |
| IH264_ERROR_T ih264_list_deinit(list_t *ps_list) |
| { |
| WORD32 retval; |
| IH264_ERROR_T ret = IH264_SUCCESS; |
| |
| ret = ih264_list_reset(ps_list); |
| RETURN_IF((ret != IH264_SUCCESS), ret); |
| |
| retval = ithread_mutex_destroy(ps_list->pv_mutex); |
| if(retval) |
| { |
| return IH264_FAIL; |
| } |
| |
| return IH264_SUCCESS; |
| } |
| |
| |
| /** |
| ******************************************************************************* |
| * |
| * @brief |
| * Terminates the list |
| * |
| * @par Description |
| * Terminates the list by setting a flag in context. |
| * |
| * @param[in] ps_list |
| * Job Queue context |
| * |
| * @returns IH264_FAIL if lock unlock fails else IH264_SUCCESS |
| * |
| * @remarks |
| * |
| ******************************************************************************* |
| */ |
| |
| IH264_ERROR_T ih264_list_terminate(list_t *ps_list) |
| { |
| IH264_ERROR_T ret = IH264_SUCCESS; |
| ret = ih264_list_lock(ps_list); |
| RETURN_IF((ret != IH264_SUCCESS), ret); |
| |
| ps_list->i4_terminate = 1; |
| |
| ret = ih264_list_unlock(ps_list); |
| RETURN_IF((ret != IH264_SUCCESS), ret); |
| return ret; |
| } |
| |
| |
| /** |
| ******************************************************************************* |
| * |
| * @brief Adds a buf to the queue |
| * |
| * @par Description |
| * Adds a buf to the queue and updates wr address to next location. |
| * Format/content of the buf structure is abstracted and hence size of the buf |
| * buffer is being passed. |
| * |
| * @param[in] ps_list |
| * Job Queue context |
| * |
| * @param[in] pv_buf |
| * Pointer to the location that contains details of the buf to be added |
| * |
| * @param[in] buf_size |
| * Size of the buf buffer |
| * |
| * @param[in] blocking |
| * To signal if the write is blocking or non-blocking. |
| * |
| * @returns |
| * |
| * @remarks |
| * Job Queue buffer is assumed to be allocated to handle worst case number of bufs |
| * Wrap around is not supported |
| * |
| ******************************************************************************* |
| */ |
| IH264_ERROR_T ih264_list_queue(list_t *ps_list, void *pv_buf, WORD32 blocking) |
| { |
| IH264_ERROR_T ret = IH264_SUCCESS; |
| IH264_ERROR_T rettmp; |
| |
| WORD32 diff; |
| void *pv_buf_wr; |
| |
| volatile WORD32 *pi4_wr_idx, *pi4_rd_idx; |
| WORD32 buf_size = ps_list->i4_entry_size; |
| |
| |
| rettmp = ih264_list_lock(ps_list); |
| RETURN_IF((rettmp != IH264_SUCCESS), rettmp); |
| |
| |
| |
| while(1) |
| { |
| /* Ensure wr idx does not go beyond rd idx by more than number of entries |
| */ |
| pi4_wr_idx = &ps_list->i4_buf_wr_idx; |
| pi4_rd_idx = &ps_list->i4_buf_rd_idx; |
| diff = *pi4_wr_idx - *pi4_rd_idx; |
| |
| if(diff < ps_list->i4_buf_max_idx) |
| { |
| WORD32 wr_idx; |
| wr_idx = ps_list->i4_buf_wr_idx & (ps_list->i4_buf_max_idx - 1); |
| pv_buf_wr = (UWORD8 *)ps_list->pv_buf_base + wr_idx * buf_size; |
| |
| memcpy(pv_buf_wr, pv_buf, buf_size); |
| ps_list->i4_buf_wr_idx++; |
| break; |
| } |
| else |
| { |
| /* wr is ahead, so wait for rd to consume */ |
| if(blocking) |
| { |
| ih264_list_yield(ps_list); |
| } |
| else |
| { |
| ret = IH264_FAIL; |
| break; |
| } |
| } |
| |
| } |
| ps_list->i4_terminate = 0; |
| |
| rettmp = ih264_list_unlock(ps_list); |
| RETURN_IF((rettmp != IH264_SUCCESS), rettmp); |
| |
| return ret; |
| } |
| /** |
| ******************************************************************************* |
| * |
| * @brief Gets next from the Job queue |
| * |
| * @par Description |
| * Gets next buf from the buf queue and updates rd address to next location. |
| * Format/content of the buf structure is abstracted and hence size of the buf |
| * buffer is being passed. If it is a blocking call and if there is no new buf |
| * then this functions unlocks the mutex and calls yield and then locks it back. |
| * and continues till a buf is available or terminate is set |
| * |
| * @param[in] ps_list |
| * Job Queue context |
| * |
| * @param[out] pv_buf |
| * Pointer to the location that contains details of the buf to be written |
| * |
| * @param[in] buf_size |
| * Size of the buf buffer |
| * |
| * @param[in] blocking |
| * To signal if the read is blocking or non-blocking. |
| * |
| * @returns |
| * |
| * @remarks |
| * Job Queue buffer is assumed to be allocated to handle worst case number of bufs |
| * Wrap around is not supported |
| * |
| ******************************************************************************* |
| */ |
| IH264_ERROR_T ih264_list_dequeue(list_t *ps_list, void *pv_buf, WORD32 blocking) |
| { |
| IH264_ERROR_T ret = IH264_SUCCESS; |
| IH264_ERROR_T rettmp; |
| WORD32 buf_size = ps_list->i4_entry_size; |
| WORD32 diff; |
| |
| void *pv_buf_rd; |
| volatile WORD32 *pi4_wr_idx, *pi4_rd_idx; |
| |
| rettmp = ih264_list_lock(ps_list); |
| RETURN_IF((rettmp != IH264_SUCCESS), rettmp); |
| |
| while(1) |
| { |
| /* Ensure wr idx is ahead of rd idx and |
| * wr idx does not go beyond rd idx by more than number of entries |
| */ |
| pi4_wr_idx = &ps_list->i4_buf_wr_idx; |
| pi4_rd_idx = &ps_list->i4_buf_rd_idx; |
| diff = *pi4_wr_idx - *pi4_rd_idx; |
| |
| |
| if(diff > 0) |
| { |
| WORD32 rd_idx; |
| rd_idx = ps_list->i4_buf_rd_idx & (ps_list->i4_buf_max_idx - 1); |
| pv_buf_rd = (UWORD8 *)ps_list->pv_buf_base + rd_idx * buf_size; |
| |
| memcpy(pv_buf, pv_buf_rd, buf_size); |
| ps_list->i4_buf_rd_idx++; |
| break; |
| } |
| else |
| { |
| /* If terminate is signaled then break */ |
| if(ps_list->i4_terminate) |
| { |
| ret = IH264_FAIL; |
| break; |
| } |
| /* wr is ahead, so wait for rd to consume */ |
| if(blocking) |
| { |
| ih264_list_yield(ps_list); |
| } |
| else |
| { |
| ret = IH264_FAIL; |
| break; |
| } |
| } |
| |
| } |
| |
| |
| rettmp = ih264_list_unlock(ps_list); |
| RETURN_IF((rettmp != IH264_SUCCESS), rettmp); |
| |
| return ret; |
| } |