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