Home | History | Annotate | Download | only in common
      1 /******************************************************************************
      2  *
      3  * Copyright (C) 2015 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at:
      8  *
      9  * http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  *
     17  *****************************************************************************
     18  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
     19 */
     20 /**
     21 *******************************************************************************
     22 * @file
     23 *  ih264_list.c
     24 *
     25 * @brief
     26 *  Contains functions for buf queue
     27 *
     28 * @author
     29 *  Harish
     30 *
     31 * @par List of Functions:
     32 *  ih264_list_size()
     33 *  ih264_list_lock()
     34 *  ih264_list_unlock()
     35 *  ih264_list_yield()
     36 *  ih264_list_free()
     37 *  ih264_list_init()
     38 *  ih264_list_reset()
     39 *  ih264_list_deinit()
     40 *  ih264_list_terminate()
     41 *  ih264_list_queue()
     42 *  ih264_list_dequeue()
     43 *
     44 * @remarks
     45 *  None
     46 *
     47 *******************************************************************************
     48 */
     49 /*****************************************************************************/
     50 /* File Includes                                                             */
     51 /*****************************************************************************/
     52 #include <stdio.h>
     53 #include <stddef.h>
     54 #include <stdlib.h>
     55 #include <string.h>
     56 #include <assert.h>
     57 
     58 #include "ih264_typedefs.h"
     59 #include "ithread.h"
     60 #include "ih264_platform_macros.h"
     61 #include "ih264_macros.h"
     62 #include "ih264_debug.h"
     63 #include "ih264_error.h"
     64 #include "ih264_list.h"
     65 
     66 /**
     67 *******************************************************************************
     68 *
     69 * @brief Returns size for buf queue context. Does not include buf queue buffer
     70 * requirements
     71 *
     72 * @par   Description
     73 * Returns size for buf queue context. Does not include buf queue buffer
     74 * requirements. Buffer size required to store the bufs should be allocated in
     75 * addition to the value returned here.
     76 *
     77 * @returns Size of the buf queue context
     78 *
     79 * @remarks
     80 *
     81 *******************************************************************************
     82 */
     83 WORD32 ih264_list_size(WORD32 num_entries, WORD32 entry_size)
     84 {
     85     WORD32 size;
     86     WORD32 clz;
     87     size = sizeof(list_t);
     88     size += ithread_get_mutex_lock_size();
     89 
     90     /* Use next power of two number of entries*/
     91     clz = CLZ(num_entries);
     92     num_entries = 1 << (32 - clz);
     93 
     94     size  += num_entries * entry_size;
     95     return size;
     96 }
     97 
     98 /**
     99 *******************************************************************************
    100 *
    101 * @brief
    102 *   Locks the list context
    103 *
    104 * @par   Description
    105 *   Locks the list context by calling ithread_mutex_lock()
    106 *
    107 * @param[in] ps_list
    108 *   Job Queue context
    109 *
    110 * @returns IH264_FAIL if mutex lock fails else IH264_SUCCESS
    111 *
    112 * @remarks
    113 *
    114 *******************************************************************************
    115 */
    116 IH264_ERROR_T ih264_list_lock(list_t *ps_list)
    117 {
    118     WORD32 retval;
    119     retval = ithread_mutex_lock(ps_list->pv_mutex);
    120     if(retval)
    121     {
    122         return IH264_FAIL;
    123     }
    124     return IH264_SUCCESS;
    125 }
    126 
    127 /**
    128 *******************************************************************************
    129 *
    130 * @brief
    131 *   Unlocks the list context
    132 *
    133 * @par   Description
    134 *   Unlocks the list context by calling ithread_mutex_unlock()
    135 *
    136 * @param[in] ps_list
    137 *   Job Queue context
    138 *
    139 * @returns IH264_FAIL if mutex unlock fails else IH264_SUCCESS
    140 *
    141 * @remarks
    142 *
    143 *******************************************************************************
    144 */
    145 
    146 IH264_ERROR_T ih264_list_unlock(list_t *ps_list)
    147 {
    148     WORD32 retval;
    149     retval = ithread_mutex_unlock(ps_list->pv_mutex);
    150     if(retval)
    151     {
    152         return IH264_FAIL;
    153     }
    154     return IH264_SUCCESS;
    155 
    156 }
    157 /**
    158 *******************************************************************************
    159 *
    160 * @brief
    161 *   Yields the thread
    162 *
    163 * @par   Description
    164 *   Unlocks the list context by calling
    165 * ih264_list_unlock(), ithread_yield() and then ih264_list_lock()
    166 * list is unlocked before to ensure the list can be accessed by other threads
    167 * If unlock is not done before calling yield then no other thread can access
    168 * the list functions and update list.
    169 *
    170 * @param[in] ps_list
    171 *   Job Queue context
    172 *
    173 * @returns IH264_FAIL if mutex lock unlock or yield fails else IH264_SUCCESS
    174 *
    175 * @remarks
    176 *
    177 *******************************************************************************
    178 */
    179 IH264_ERROR_T ih264_list_yield(list_t *ps_list)
    180 {
    181 
    182     IH264_ERROR_T ret = IH264_SUCCESS;
    183 
    184     IH264_ERROR_T rettmp;
    185     rettmp = ih264_list_unlock(ps_list);
    186     RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
    187 
    188     ithread_yield();
    189 
    190     if(ps_list->i4_yeild_interval_us > 0)
    191         ithread_usleep(ps_list->i4_yeild_interval_us);
    192 
    193     rettmp = ih264_list_lock(ps_list);
    194     RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
    195     return ret;
    196 }
    197 
    198 
    199 /**
    200 *******************************************************************************
    201 *
    202 * @brief free the buf queue pointers
    203 *
    204 * @par   Description
    205 * Frees the list context
    206 *
    207 * @param[in] pv_buf
    208 * Memory for buf queue buffer and buf queue context
    209 *
    210 * @returns Pointer to buf queue context
    211 *
    212 * @remarks
    213 * Since it will be called only once by master thread this is not thread safe.
    214 *
    215 *******************************************************************************
    216 */
    217 IH264_ERROR_T ih264_list_free(list_t *ps_list)
    218 {
    219     WORD32 ret;
    220     ret = ithread_mutex_destroy(ps_list->pv_mutex);
    221 
    222     if(0 == ret)
    223         return IH264_SUCCESS;
    224     else
    225         return IH264_FAIL;
    226 }
    227 
    228 /**
    229 *******************************************************************************
    230 *
    231 * @brief Initialize the buf queue
    232 *
    233 * @par   Description
    234 * Initializes the list context and sets write and read pointers to start of
    235 * buf queue buffer
    236 *
    237 * @param[in] pv_buf
    238 * Memoy for buf queue buffer and buf queue context
    239 *
    240 * @param[in] buf_size
    241 * Size of the total memory allocated
    242 *
    243 * @returns Pointer to buf queue context
    244 *
    245 * @remarks
    246 * Since it will be called only once by master thread this is not thread safe.
    247 *
    248 *******************************************************************************
    249 */
    250 void* ih264_list_init(void *pv_buf,
    251                       WORD32 buf_size,
    252                       WORD32 num_entries,
    253                       WORD32 entry_size,
    254                       WORD32 yeild_interval_us)
    255 {
    256     list_t *ps_list;
    257     UWORD8 *pu1_buf;
    258 
    259     pu1_buf = (UWORD8 *)pv_buf;
    260 
    261     ps_list = (list_t *)pu1_buf;
    262     pu1_buf += sizeof(list_t);
    263     buf_size -= sizeof(list_t);
    264 
    265     ps_list->pv_mutex = pu1_buf;
    266     pu1_buf += ithread_get_mutex_lock_size();
    267     buf_size -= ithread_get_mutex_lock_size();
    268 
    269     if (buf_size <= 0)
    270       return NULL;
    271 
    272     ithread_mutex_init(ps_list->pv_mutex);
    273 
    274     /* Ensure num_entries is power of two */
    275     ASSERT(0 == (num_entries & (num_entries - 1)));
    276 
    277     /* Ensure remaining buffer is large enough to hold given number of entries */
    278     ASSERT((num_entries * entry_size) <= buf_size);
    279 
    280     ps_list->pv_buf_base = pu1_buf;
    281     ps_list->i4_terminate = 0;
    282     ps_list->i4_entry_size = entry_size;
    283     ps_list->i4_buf_rd_idx = 0;
    284     ps_list->i4_buf_wr_idx = 0;
    285     ps_list->i4_log2_buf_max_idx = 32 - CLZ(num_entries);
    286     ps_list->i4_buf_max_idx = num_entries;
    287     ps_list->i4_yeild_interval_us = yeild_interval_us;
    288 
    289     return ps_list;
    290 }
    291 /**
    292 *******************************************************************************
    293 *
    294 * @brief
    295 *   Resets the list context
    296 *
    297 * @par   Description
    298 *   Resets the list context by initializing buf queue context elements
    299 *
    300 * @param[in] ps_list
    301 *   Job Queue context
    302 *
    303 * @returns IH264_FAIL if lock unlock fails else IH264_SUCCESS
    304 *
    305 * @remarks
    306 *
    307 *******************************************************************************
    308 */
    309 IH264_ERROR_T ih264_list_reset(list_t *ps_list)
    310 {
    311     IH264_ERROR_T ret = IH264_SUCCESS;
    312     ret = ih264_list_lock(ps_list);
    313     RETURN_IF((ret != IH264_SUCCESS), ret);
    314 
    315     ps_list->i4_terminate  = 0;
    316     ps_list->i4_buf_rd_idx = 0;
    317     ps_list->i4_buf_wr_idx = 0;
    318 
    319     ret = ih264_list_unlock(ps_list);
    320     RETURN_IF((ret != IH264_SUCCESS), ret);
    321 
    322     return ret;
    323 }
    324 
    325 /**
    326 *******************************************************************************
    327 *
    328 * @brief
    329 *   Deinitializes the list context
    330 *
    331 * @par   Description
    332 *   Deinitializes the list context by calling ih264_list_reset()
    333 * and then destrying the mutex created
    334 *
    335 * @param[in] ps_list
    336 *   Job Queue context
    337 *
    338 * @returns IH264_FAIL if lock unlock fails else IH264_SUCCESS
    339 *
    340 * @remarks
    341 *
    342 *******************************************************************************
    343 */
    344 IH264_ERROR_T ih264_list_deinit(list_t *ps_list)
    345 {
    346     WORD32 retval;
    347     IH264_ERROR_T ret = IH264_SUCCESS;
    348 
    349     ret = ih264_list_reset(ps_list);
    350     RETURN_IF((ret != IH264_SUCCESS), ret);
    351 
    352     retval = ithread_mutex_destroy(ps_list->pv_mutex);
    353     if(retval)
    354     {
    355         return IH264_FAIL;
    356     }
    357 
    358     return IH264_SUCCESS;
    359 }
    360 
    361 
    362 /**
    363 *******************************************************************************
    364 *
    365 * @brief
    366 *   Terminates the list
    367 *
    368 * @par   Description
    369 *   Terminates the list by setting a flag in context.
    370 *
    371 * @param[in] ps_list
    372 *   Job Queue context
    373 *
    374 * @returns IH264_FAIL if lock unlock fails else IH264_SUCCESS
    375 *
    376 * @remarks
    377 *
    378 *******************************************************************************
    379 */
    380 
    381 IH264_ERROR_T ih264_list_terminate(list_t *ps_list)
    382 {
    383     IH264_ERROR_T ret = IH264_SUCCESS;
    384     ret = ih264_list_lock(ps_list);
    385     RETURN_IF((ret != IH264_SUCCESS), ret);
    386 
    387     ps_list->i4_terminate = 1;
    388 
    389     ret = ih264_list_unlock(ps_list);
    390     RETURN_IF((ret != IH264_SUCCESS), ret);
    391     return ret;
    392 }
    393 
    394 
    395 /**
    396 *******************************************************************************
    397 *
    398 * @brief Adds a buf to the queue
    399 *
    400 * @par   Description
    401 * Adds a buf to the queue and updates wr address to next location.
    402 * Format/content of the buf structure is abstracted and hence size of the buf
    403 * buffer is being passed.
    404 *
    405 * @param[in] ps_list
    406 *   Job Queue context
    407 *
    408 * @param[in] pv_buf
    409 *   Pointer to the location that contains details of the buf to be added
    410 *
    411 * @param[in] buf_size
    412 *   Size of the buf buffer
    413 *
    414 * @param[in] blocking
    415 *   To signal if the write is blocking or non-blocking.
    416 *
    417 * @returns
    418 *
    419 * @remarks
    420 * Job Queue buffer is assumed to be allocated to handle worst case number of bufs
    421 * Wrap around is not supported
    422 *
    423 *******************************************************************************
    424 */
    425 IH264_ERROR_T ih264_list_queue(list_t *ps_list, void *pv_buf, WORD32 blocking)
    426 {
    427     IH264_ERROR_T ret = IH264_SUCCESS;
    428     IH264_ERROR_T rettmp;
    429 
    430     WORD32 diff;
    431     void *pv_buf_wr;
    432 
    433     volatile WORD32 *pi4_wr_idx, *pi4_rd_idx;
    434     WORD32 buf_size = ps_list->i4_entry_size;
    435 
    436 
    437     rettmp = ih264_list_lock(ps_list);
    438     RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
    439 
    440 
    441 
    442     while(1)
    443     {
    444         /* Ensure wr idx does not go beyond rd idx by more than number of entries
    445          */
    446         pi4_wr_idx = &ps_list->i4_buf_wr_idx;
    447         pi4_rd_idx = &ps_list->i4_buf_rd_idx;
    448         diff = *pi4_wr_idx - *pi4_rd_idx;
    449 
    450         if(diff < ps_list->i4_buf_max_idx)
    451         {
    452             WORD32 wr_idx;
    453             wr_idx = ps_list->i4_buf_wr_idx & (ps_list->i4_buf_max_idx - 1);
    454             pv_buf_wr = (UWORD8 *)ps_list->pv_buf_base + wr_idx * buf_size;
    455 
    456             memcpy(pv_buf_wr, pv_buf, buf_size);
    457             ps_list->i4_buf_wr_idx++;
    458             break;
    459         }
    460         else
    461         {
    462             /* wr is ahead, so wait for rd to consume */
    463             if(blocking)
    464             {
    465                 ih264_list_yield(ps_list);
    466             }
    467             else
    468             {
    469                 ret = IH264_FAIL;
    470                 break;
    471             }
    472         }
    473 
    474     }
    475     ps_list->i4_terminate = 0;
    476 
    477     rettmp = ih264_list_unlock(ps_list);
    478     RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
    479 
    480     return ret;
    481 }
    482 /**
    483 *******************************************************************************
    484 *
    485 * @brief Gets next from the Job queue
    486 *
    487 * @par   Description
    488 * Gets next buf from the buf queue and updates rd address to next location.
    489 * Format/content of the buf structure is abstracted and hence size of the buf
    490 * buffer is being passed. If it is a blocking call and if there is no new buf
    491 * then this functions unlocks the mutex and calls yield and then locks it back.
    492 * and continues till a buf is available or terminate is set
    493 *
    494 * @param[in] ps_list
    495 *   Job Queue context
    496 *
    497 * @param[out] pv_buf
    498 *   Pointer to the location that contains details of the buf to be written
    499 *
    500 * @param[in] buf_size
    501 *   Size of the buf buffer
    502 *
    503 * @param[in] blocking
    504 *   To signal if the read is blocking or non-blocking.
    505 *
    506 * @returns
    507 *
    508 * @remarks
    509 * Job Queue buffer is assumed to be allocated to handle worst case number of bufs
    510 * Wrap around is not supported
    511 *
    512 *******************************************************************************
    513 */
    514 IH264_ERROR_T ih264_list_dequeue(list_t *ps_list, void *pv_buf, WORD32 blocking)
    515 {
    516     IH264_ERROR_T ret = IH264_SUCCESS;
    517     IH264_ERROR_T rettmp;
    518     WORD32 buf_size = ps_list->i4_entry_size;
    519     WORD32 diff;
    520 
    521     void *pv_buf_rd;
    522     volatile WORD32 *pi4_wr_idx, *pi4_rd_idx;
    523 
    524     rettmp = ih264_list_lock(ps_list);
    525     RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
    526 
    527     while(1)
    528     {
    529         /* Ensure wr idx is ahead of rd idx and
    530          * wr idx does not go beyond rd idx by more than number of entries
    531          */
    532         pi4_wr_idx = &ps_list->i4_buf_wr_idx;
    533         pi4_rd_idx = &ps_list->i4_buf_rd_idx;
    534         diff = *pi4_wr_idx - *pi4_rd_idx;
    535 
    536 
    537         if(diff > 0)
    538         {
    539             WORD32 rd_idx;
    540             rd_idx = ps_list->i4_buf_rd_idx & (ps_list->i4_buf_max_idx - 1);
    541             pv_buf_rd = (UWORD8 *)ps_list->pv_buf_base + rd_idx * buf_size;
    542 
    543             memcpy(pv_buf, pv_buf_rd, buf_size);
    544             ps_list->i4_buf_rd_idx++;
    545             break;
    546         }
    547         else
    548         {
    549             /* If terminate is signaled then break */
    550             if(ps_list->i4_terminate)
    551             {
    552                 ret = IH264_FAIL;
    553                 break;
    554             }
    555             /* wr is ahead, so wait for rd to consume */
    556             if(blocking)
    557             {
    558                 ih264_list_yield(ps_list);
    559             }
    560             else
    561             {
    562                 ret = IH264_FAIL;
    563                 break;
    564             }
    565         }
    566 
    567     }
    568 
    569 
    570     rettmp = ih264_list_unlock(ps_list);
    571     RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
    572 
    573     return ret;
    574 }
    575