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