• Home
  • History
  • Annotate
  • 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