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*/ 70WORD32 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*/ 96IV_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 126IV_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*/ 159IV_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*/ 195IV_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*/ 228void* 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*/ 274IV_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*/ 308IV_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 345IV_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*/ 389IV_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*/ 463IV_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