Home | History | Annotate | Download | only in decoder
      1 /******************************************************************************
      2 *
      3 * Copyright (C) 2012 Ittiam Systems Pvt Ltd, Bangalore
      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 /**
     19 *******************************************************************************
     20 * @file
     21 *  ihevcd_job_queue.c
     22 *
     23 * @brief
     24 *  Contains functions for job queue
     25 *
     26 * @author
     27 *  Harish
     28 *
     29 * @par List of Functions:
     30 *
     31 * @remarks
     32 *  None
     33 *
     34 *******************************************************************************
     35 */
     36 /*****************************************************************************/
     37 /* File Includes                                                             */
     38 /*****************************************************************************/
     39 #include <stdio.h>
     40 #include <stddef.h>
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include <assert.h>
     44 
     45 #include "ihevc_typedefs.h"
     46 #include "iv.h"
     47 #include "ivd.h"
     48 #include "ihevcd_cxa.h"
     49 #include "ithread.h"
     50 #include "ihevc_platform_macros.h"
     51 
     52 #include "ihevc_macros.h"
     53 #include "ihevcd_error.h"
     54 #include "ihevcd_job_queue.h"
     55 
     56 /**
     57 *******************************************************************************
     58 *
     59 * @brief Returns size for job queue context. Does not include job queue buffer
     60 * requirements
     61 *
     62 * @par   Description
     63 * Returns size for job queue context. Does not include job queue buffer
     64 * requirements. Buffer size required to store the jobs should be allocated in
     65 * addition to the value returned here.
     66 *
     67 * @returns Size of the job queue context
     68 *
     69 * @remarks
     70 *
     71 *******************************************************************************
     72 */
     73 WORD32 ihevcd_jobq_ctxt_size()
     74 {
     75     WORD32 size;
     76     size = sizeof(jobq_t);
     77     size += ithread_get_mutex_lock_size();
     78     return size;
     79 }
     80 
     81 /**
     82 *******************************************************************************
     83 *
     84 * @brief
     85 *   Locks the jobq conext
     86 *
     87 * @par   Description
     88 *   Locks the jobq conext by calling ithread_mutex_lock()
     89 *
     90 * @param[in] ps_jobq
     91 *   Job Queue context
     92 *
     93 * @returns IHEVCD_FAIL if mutex lock fails else IHEVCD_SUCCESS
     94 *
     95 * @remarks
     96 *
     97 *******************************************************************************
     98 */
     99 IHEVCD_ERROR_T ihevcd_jobq_lock(jobq_t *ps_jobq)
    100 {
    101     WORD32 retval;
    102     retval = ithread_mutex_lock(ps_jobq->pv_mutex);
    103     if(retval)
    104     {
    105         return (IHEVCD_ERROR_T)IHEVCD_FAIL;
    106     }
    107     return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    108 }
    109 
    110 /**
    111 *******************************************************************************
    112 *
    113 * @brief
    114 *   Unlocks the jobq conext
    115 *
    116 * @par   Description
    117 *   Unlocks the jobq conext by calling ithread_mutex_unlock()
    118 *
    119 * @param[in] ps_jobq
    120 *   Job Queue context
    121 *
    122 * @returns IHEVCD_FAIL if mutex unlock fails else IHEVCD_SUCCESS
    123 *
    124 * @remarks
    125 *
    126 *******************************************************************************
    127 */
    128 
    129 IHEVCD_ERROR_T ihevcd_jobq_unlock(jobq_t *ps_jobq)
    130 {
    131     WORD32 retval;
    132     retval = ithread_mutex_unlock(ps_jobq->pv_mutex);
    133     if(retval)
    134     {
    135         return (IHEVCD_ERROR_T)IHEVCD_FAIL;
    136     }
    137     return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    138 
    139 }
    140 /**
    141 *******************************************************************************
    142 *
    143 * @brief
    144 *   Yeilds the thread
    145 *
    146 * @par   Description
    147 *   Unlocks the jobq conext by calling
    148 * ihevcd_jobq_unlock(), ithread_yield() and then ihevcd_jobq_lock()
    149 * jobq is unlocked before to ensure the jobq can be accessed by other threads
    150 * If unlock is not done before calling yield then no other thread can access
    151 * the jobq functions and update jobq.
    152 *
    153 * @param[in] ps_jobq
    154 *   Job Queue context
    155 *
    156 * @returns IHEVCD_FAIL if mutex lock unlock or yield fails else IHEVCD_SUCCESS
    157 *
    158 * @remarks
    159 *
    160 *******************************************************************************
    161 */
    162 IHEVCD_ERROR_T ihevcd_jobq_yield(jobq_t *ps_jobq)
    163 {
    164 
    165     IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    166 
    167     IHEVCD_ERROR_T rettmp;
    168     rettmp = ihevcd_jobq_unlock(ps_jobq);
    169     RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
    170 
    171     //NOP(1024 * 8);
    172     ithread_yield();
    173 
    174     rettmp = ihevcd_jobq_lock(ps_jobq);
    175     RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
    176     return ret;
    177 }
    178 
    179 
    180 /**
    181 *******************************************************************************
    182 *
    183 * @brief free the job queue pointers
    184 *
    185 * @par   Description
    186 * Frees the jobq context
    187 *
    188 * @param[in] pv_buf
    189 * Memoy for job queue buffer and job queue context
    190 *
    191 * @returns Pointer to job queue context
    192 *
    193 * @remarks
    194 * Since it will be called only once by master thread this is not thread safe.
    195 *
    196 *******************************************************************************
    197 */
    198 IHEVCD_ERROR_T ihevcd_jobq_free(jobq_t *ps_jobq)
    199 {
    200     WORD32 ret;
    201     ret = ithread_mutex_destroy(ps_jobq->pv_mutex);
    202 
    203     if(0 == ret)
    204         return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    205     else
    206         return (IHEVCD_ERROR_T)IHEVCD_FAIL;
    207 }
    208 
    209 /**
    210 *******************************************************************************
    211 *
    212 * @brief Initialize the job queue
    213 *
    214 * @par   Description
    215 * Initializes the jobq context and sets write and read pointers to start of
    216 * job queue buffer
    217 *
    218 * @param[in] pv_buf
    219 * Memoy for job queue buffer and job queue context
    220 *
    221 * @param[in] buf_size
    222 * Size of the total memory allocated
    223 *
    224 * @returns Pointer to job queue context
    225 *
    226 * @remarks
    227 * Since it will be called only once by master thread this is not thread safe.
    228 *
    229 *******************************************************************************
    230 */
    231 void* ihevcd_jobq_init(void *pv_buf, WORD32 buf_size)
    232 {
    233     jobq_t *ps_jobq;
    234     UWORD8 *pu1_buf;
    235     pu1_buf = (UWORD8 *)pv_buf;
    236 
    237     ps_jobq = (jobq_t *)pu1_buf;
    238     pu1_buf += sizeof(jobq_t);
    239     buf_size -= sizeof(jobq_t);
    240 
    241     ps_jobq->pv_mutex = pu1_buf;
    242     pu1_buf += ithread_get_mutex_lock_size();
    243     buf_size -= ithread_get_mutex_lock_size();
    244 
    245     if(buf_size <= 0)
    246         return NULL;
    247 
    248     ithread_mutex_init(ps_jobq->pv_mutex);
    249 
    250     ps_jobq->pv_buf_base = pu1_buf;
    251     ps_jobq->pv_buf_wr = pu1_buf;
    252     ps_jobq->pv_buf_rd = pu1_buf;
    253     ps_jobq->pv_buf_end = pu1_buf + buf_size;
    254     ps_jobq->i4_terminate = 0;
    255 
    256 
    257     return ps_jobq;
    258 }
    259 /**
    260 *******************************************************************************
    261 *
    262 * @brief
    263 *   Resets the jobq conext
    264 *
    265 * @par   Description
    266 *   Resets the jobq conext by initilizing job queue context elements
    267 *
    268 * @param[in] ps_jobq
    269 *   Job Queue context
    270 *
    271 * @returns IHEVCD_FAIL if lock unlock fails else IHEVCD_SUCCESS
    272 *
    273 * @remarks
    274 *
    275 *******************************************************************************
    276 */
    277 IHEVCD_ERROR_T ihevcd_jobq_reset(jobq_t *ps_jobq)
    278 {
    279     IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    280     ret = ihevcd_jobq_lock(ps_jobq);
    281     RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
    282 
    283     ps_jobq->pv_buf_wr      = ps_jobq->pv_buf_base;
    284     ps_jobq->pv_buf_rd      = ps_jobq->pv_buf_base;
    285     ps_jobq->i4_terminate   = 0;
    286     ret = ihevcd_jobq_unlock(ps_jobq);
    287     RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
    288 
    289     return ret;
    290 }
    291 
    292 /**
    293 *******************************************************************************
    294 *
    295 * @brief
    296 *   Deinitializes the jobq conext
    297 *
    298 * @par   Description
    299 *   Deinitializes the jobq conext by calling ihevc_jobq_reset()
    300 * and then destrying the mutex created
    301 *
    302 * @param[in] ps_jobq
    303 *   Job Queue context
    304 *
    305 * @returns IHEVCD_FAIL if lock unlock fails else IHEVCD_SUCCESS
    306 *
    307 * @remarks
    308 *
    309 *******************************************************************************
    310 */
    311 IHEVCD_ERROR_T ihevcd_jobq_deinit(jobq_t *ps_jobq)
    312 {
    313     WORD32 retval;
    314     IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    315 
    316     ret = ihevcd_jobq_reset(ps_jobq);
    317     RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
    318 
    319     retval = ithread_mutex_destroy(ps_jobq->pv_mutex);
    320     if(retval)
    321     {
    322         return (IHEVCD_ERROR_T)IHEVCD_FAIL;
    323     }
    324 
    325     return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    326 }
    327 
    328 
    329 /**
    330 *******************************************************************************
    331 *
    332 * @brief
    333 *   Terminates the jobq
    334 *
    335 * @par   Description
    336 *   Terminates the jobq by setting a flag in context.
    337 *
    338 * @param[in] ps_jobq
    339 *   Job Queue context
    340 *
    341 * @returns IHEVCD_FAIL if lock unlock fails else IHEVCD_SUCCESS
    342 *
    343 * @remarks
    344 *
    345 *******************************************************************************
    346 */
    347 
    348 IHEVCD_ERROR_T ihevcd_jobq_terminate(jobq_t *ps_jobq)
    349 {
    350     IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    351     ret = ihevcd_jobq_lock(ps_jobq);
    352     RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
    353 
    354     ps_jobq->i4_terminate = 1;
    355 
    356     ret = ihevcd_jobq_unlock(ps_jobq);
    357     RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
    358     return ret;
    359 }
    360 
    361 
    362 /**
    363 *******************************************************************************
    364 *
    365 * @brief Adds a job to the queue
    366 *
    367 * @par   Description
    368 * Adds a job to the queue and updates wr address to next location.
    369 * Format/content of the job structure is abstracted and hence size of the job
    370 * buffer is being passed.
    371 *
    372 * @param[in] ps_jobq
    373 *   Job Queue context
    374 *
    375 * @param[in] pv_job
    376 *   Pointer to the location that contains details of the job to be added
    377 *
    378 * @param[in] job_size
    379 *   Size of the job buffer
    380 *
    381 * @param[in] blocking
    382 *   To signal if the write is blocking or non-blocking.
    383 *
    384 * @returns
    385 *
    386 * @remarks
    387 * Job Queue buffer is assumed to be allocated to handle worst case number of jobs
    388 * Wrap around is not supported
    389 *
    390 *******************************************************************************
    391 */
    392 IHEVCD_ERROR_T ihevcd_jobq_queue(jobq_t *ps_jobq, void *pv_job, WORD32 job_size, WORD32 blocking)
    393 {
    394     IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    395     IHEVCD_ERROR_T rettmp;
    396     UWORD8 *pu1_buf;
    397     UNUSED(blocking);
    398 
    399     rettmp = ihevcd_jobq_lock(ps_jobq);
    400     RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
    401 
    402     pu1_buf = (UWORD8 *)ps_jobq->pv_buf_wr;
    403     if((UWORD8 *)ps_jobq->pv_buf_end >= (pu1_buf + job_size))
    404     {
    405         memcpy(ps_jobq->pv_buf_wr, pv_job, job_size);
    406         ps_jobq->pv_buf_wr = (UWORD8 *)ps_jobq->pv_buf_wr + job_size;
    407         ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    408     }
    409     else
    410     {
    411         /* Handle wrap around case */
    412         /* Wait for pv_buf_rd to consume first job_size number of bytes
    413          * from the beginning of job queue
    414          */
    415         ret = (IHEVCD_ERROR_T)IHEVCD_FAIL;
    416     }
    417 
    418     ps_jobq->i4_terminate = 0;
    419 
    420     rettmp = ihevcd_jobq_unlock(ps_jobq);
    421     RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
    422 
    423     return ret;
    424 }
    425 /**
    426 *******************************************************************************
    427 *
    428 * @brief Gets next from the Job queue
    429 *
    430 * @par   Description
    431 * Gets next job from the job queue and updates rd address to next location.
    432 * Format/content of the job structure is abstracted and hence size of the job
    433 * buffer is being passed. If it is a blocking call and if there is no new job
    434 * then this functions unlocks the mutext and calls yield and then locks it back.
    435 * and continues till a job is available or terminate is set
    436 *
    437 * @param[in] ps_jobq
    438 *   Job Queue context
    439 *
    440 * @param[out] pv_job
    441 *   Pointer to the location that contains details of the job to be written
    442 *
    443 * @param[in] job_size
    444 *   Size of the job buffer
    445 *
    446 * @param[in] blocking
    447 *   To signal if the read is blocking or non-blocking.
    448 *
    449 * @returns
    450 *
    451 * @remarks
    452 * Job Queue buffer is assumed to be allocated to handle worst case number of jobs
    453 * Wrap around is not supported
    454 *
    455 *******************************************************************************
    456 */
    457 IHEVCD_ERROR_T ihevcd_jobq_dequeue(jobq_t *ps_jobq, void *pv_job, WORD32 job_size, WORD32 blocking)
    458 {
    459     IHEVCD_ERROR_T ret;
    460     IHEVCD_ERROR_T rettmp;
    461     volatile UWORD8 *pu1_buf;
    462 
    463     rettmp = ihevcd_jobq_lock(ps_jobq);
    464     RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
    465     pu1_buf = (UWORD8 *)ps_jobq->pv_buf_rd;
    466 
    467 
    468     if((UWORD8 *)ps_jobq->pv_buf_end >= (pu1_buf + job_size))
    469     {
    470         while(1)
    471         {
    472             pu1_buf = (UWORD8 *)ps_jobq->pv_buf_rd;
    473             if((UWORD8 *)ps_jobq->pv_buf_wr >= (pu1_buf + job_size))
    474             {
    475                 memcpy(pv_job, ps_jobq->pv_buf_rd, job_size);
    476                 ps_jobq->pv_buf_rd = (UWORD8 *)ps_jobq->pv_buf_rd + job_size;
    477                 ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    478                 break;
    479             }
    480             else
    481             {
    482                 /* If all the entries have been dequeued, then break and return */
    483                 if(1 == ps_jobq->i4_terminate)
    484                 {
    485                     ret = (IHEVCD_ERROR_T)IHEVCD_FAIL;
    486                     break;
    487                 }
    488 
    489                 if(1 == blocking)
    490                 {
    491                     ihevcd_jobq_yield(ps_jobq);
    492 
    493                 }
    494                 else
    495                 {
    496                     /* If there is no job available,
    497                      * and this is non blocking call then return fail */
    498                     ret = (IHEVCD_ERROR_T)IHEVCD_FAIL;
    499                 }
    500             }
    501         }
    502     }
    503     else
    504     {
    505         /* Handle wrap around case */
    506         /* Wait for pv_buf_rd to consume first job_size number of bytes
    507          * from the beginning of job queue
    508          */
    509         ret = (IHEVCD_ERROR_T)IHEVCD_FAIL;
    510     }
    511     rettmp = ihevcd_jobq_unlock(ps_jobq);
    512     RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
    513 
    514     return ret;
    515 }
    516