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 */
ih264_list_size(WORD32 num_entries,WORD32 entry_size)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 */
ih264_list_lock(list_t * ps_list)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
ih264_list_unlock(list_t * ps_list)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 */
ih264_list_yield(list_t * ps_list)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 */
ih264_list_free(list_t * ps_list)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 */
ih264_list_init(void * pv_buf,WORD32 buf_size,WORD32 num_entries,WORD32 entry_size,WORD32 yeild_interval_us)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 */
ih264_list_reset(list_t * ps_list)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 */
ih264_list_deinit(list_t * ps_list)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
ih264_list_terminate(list_t * ps_list)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 */
ih264_list_queue(list_t * ps_list,void * pv_buf,WORD32 blocking)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 */
ih264_list_dequeue(list_t * ps_list,void * pv_buf,WORD32 blocking)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