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