• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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