blob: 736b41c465428ce509554923fe3bb10ac4b78cbf [file] [log] [blame]
Hamsalekha S8d3d3032015-03-13 21:24:58 +05301/******************************************************************************
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*/
83WORD32 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*/
116IH264_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
146IH264_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*/
179IH264_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*/
217IH264_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*/
250void* 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*/
309IH264_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*/
344IH264_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
381IH264_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*/
425IH264_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*/
514IH264_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}