Coverage Report

Created: 2025-11-12 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libavc/common/ih264_list.c
Line
Count
Source
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
*******************************************************************************
23
* @file
24
*  ih264_list.c
25
*
26
* @brief
27
*  Contains functions for buf queue
28
*
29
* @author
30
*  ittiam
31
*
32
* @par List of Functions:
33
*  - ih264_list_size
34
*  - ih264_list_lock
35
*  - ih264_list_unlock
36
*  - ih264_list_yield
37
*  - ih264_list_free
38
*  - ih264_list_init
39
*  - ih264_list_reset
40
*  - ih264_list_deinit
41
*  - ih264_list_terminate
42
*  - ih264_list_queue
43
*  - ih264_list_dequeue
44
*
45
* @remarks
46
*  none
47
*
48
*******************************************************************************
49
*/
50
51
/*****************************************************************************/
52
/* File Includes                                                             */
53
/*****************************************************************************/
54
55
/* System Include Files */
56
#include <stdio.h>
57
#include <stddef.h>
58
#include <stdlib.h>
59
#include <string.h>
60
#include <assert.h>
61
62
/* User Include Files */
63
#include "ih264_typedefs.h"
64
#include "ithread.h"
65
#include "ih264_debug.h"
66
#include "ih264_macros.h"
67
#include "ih264_error.h"
68
#include "ih264_list.h"
69
#include "ih264_platform_macros.h"
70
71
/*****************************************************************************/
72
/* Function Definitions                                                      */
73
/*****************************************************************************/
74
75
/**
76
*******************************************************************************
77
*
78
* @brief Returns size for job queue context.
79
*
80
* @par Description
81
*  Returns size for job queue context.
82
*
83
* @param[in] num_entries
84
*  max number of jobs that can be queued
85
*
86
* @param[in] entry_size
87
*  memory needed for a single job
88
*
89
* @returns Size of the job queue context
90
*
91
* @remarks
92
*
93
*******************************************************************************
94
*/
95
WORD32 ih264_list_size(WORD32 num_entries, WORD32 entry_size)
96
37.4k
{
97
37.4k
    WORD32 size;
98
37.4k
    WORD32 clz;
99
100
37.4k
    size = sizeof(list_t);
101
37.4k
    size += ithread_get_mutex_lock_size();
102
103
    /* Use next power of two number of entries*/
104
37.4k
    clz = CLZ(num_entries);
105
37.4k
    num_entries = 1 << (32 - clz);
106
107
37.4k
    size += num_entries * entry_size;
108
37.4k
    return size;
109
37.4k
}
110
111
/**
112
*******************************************************************************
113
*
114
* @brief Locks the list context
115
*
116
* @par Description
117
*  Locks the list context by calling ithread_mutex_lock()
118
*
119
* @param[in] ps_list
120
*  Pointer to job queue context
121
*
122
* @returns IH264_FAIL if mutex lock fails else IH264_SUCCESS
123
*
124
* @remarks
125
*
126
*******************************************************************************
127
*/
128
IH264_ERROR_T ih264_list_lock(list_t *ps_list)
129
82.7M
{
130
82.7M
    WORD32 retval;
131
132
82.7M
    retval = ithread_mutex_lock(ps_list->pv_mutex);
133
82.7M
    if(retval)
134
0
        return IH264_FAIL;
135
82.7M
    return IH264_SUCCESS;
136
82.7M
}
137
138
/**
139
*******************************************************************************
140
*
141
* @brief Unlocks the list context
142
*
143
* @par Description
144
*  Unlocks the list context by calling ithread_mutex_unlock()
145
*
146
* @param[in] ps_list
147
*  Pointer to job queue context
148
*
149
* @returns IH264_FAIL if mutex unlock fails else IH264_SUCCESS
150
*
151
* @remarks
152
*
153
*******************************************************************************
154
*/
155
IH264_ERROR_T ih264_list_unlock(list_t *ps_list)
156
82.7M
{
157
82.7M
    WORD32 retval;
158
159
82.7M
    retval = ithread_mutex_unlock(ps_list->pv_mutex);
160
82.7M
    if(retval)
161
0
        return IH264_FAIL;
162
82.7M
    return IH264_SUCCESS;
163
82.7M
}
164
165
/**
166
*******************************************************************************
167
*
168
* @brief Yields the thread
169
*
170
* @par Description
171
*  Unlocks the list context by calling  ih264_list_unlock(), ithread_yield()
172
*  and then ih264_list_lock(). List is unlocked before to ensure its
173
*  access by other threads. If unlock is not done before calling yield then
174
*  no other thread can access the list functions and update list.
175
*
176
* @param[in] ps_list
177
*  pointer to Job Queue context
178
*
179
* @returns IH264_FAIL if mutex lock unlock or yield fails else IH264_SUCCESS
180
*
181
* @remarks
182
*
183
*******************************************************************************
184
*/
185
IH264_ERROR_T ih264_list_yield(list_t *ps_list)
186
171k
{
187
171k
    IH264_ERROR_T ret;
188
189
171k
    ret = ih264_list_unlock(ps_list);
190
171k
    RETURN_IF((ret != IH264_SUCCESS), ret);
191
192
171k
    ithread_yield();
193
194
171k
    if(ps_list->i4_yield_interval_us > 0)
195
171k
        ithread_usleep(ps_list->i4_yield_interval_us);
196
197
171k
    ret = ih264_list_lock(ps_list);
198
171k
    RETURN_IF((ret != IH264_SUCCESS), ret);
199
171k
    return IH264_SUCCESS;
200
171k
}
201
202
/**
203
*******************************************************************************
204
*
205
* @brief free the list context
206
*
207
* @par Description
208
*  Frees the list context
209
*
210
* @param[in] ps_list
211
*  pointer to Job Queue context
212
*
213
* @returns IH264_FAIL if mutex desttroy fails else IH264_SUCCESS
214
*
215
* @remarks
216
*  Since it will be called only once by master thread this is not thread safe.
217
*
218
*******************************************************************************
219
*/
220
IH264_ERROR_T ih264_list_free(list_t *ps_list)
221
8.23k
{
222
8.23k
    WORD32 ret;
223
224
8.23k
    ret = ithread_mutex_destroy(ps_list->pv_mutex);
225
8.23k
    if(0 == ret)
226
8.23k
        return IH264_SUCCESS;
227
0
    return IH264_FAIL;
228
8.23k
}
229
230
/**
231
*******************************************************************************
232
*
233
* @brief Initialize the buf queue
234
*
235
* @par Description
236
*  Initializes the list context and sets write and read pointers to start of
237
*  buf queue buffer
238
*
239
* @param[in] pv_buf
240
*  Memory for job queue context
241
*
242
* @param[in] buf_size
243
*  Size of the total memory allocated
244
*
245
* @param[in] num_entries
246
*  max number of jobs that can be queued
247
*
248
* @param[in] entry_size
249
*  memory needed for a single job
250
*
251
* @param[in] yield_interval_us
252
*  Thread sleep duration
253
*
254
* @returns Pointer to job queue context
255
*
256
* @remarks
257
*  Since it will be called only once by master thread this is not thread safe.
258
*
259
*******************************************************************************
260
*/
261
void* ih264_list_init(void *pv_buf,
262
                      WORD32 buf_size,
263
                      WORD32 num_entries,
264
                      WORD32 entry_size,
265
                      WORD32 yield_interval_us)
266
18.6k
{
267
18.6k
    list_t *ps_list = (list_t *)pv_buf;
268
18.6k
    UWORD8 *pu1_buf = (UWORD8 *)pv_buf;
269
270
18.6k
    pu1_buf += sizeof(list_t);
271
18.6k
    buf_size -= sizeof(list_t);
272
273
18.6k
    ps_list->pv_mutex = pu1_buf;
274
18.6k
    pu1_buf += ithread_get_mutex_lock_size();
275
18.6k
    buf_size -= ithread_get_mutex_lock_size();
276
277
18.6k
    if (buf_size <= 0)
278
0
      return NULL;
279
280
18.6k
    ithread_mutex_init(ps_list->pv_mutex);
281
282
    /* Ensure num_entries is power of two */
283
18.6k
    ASSERT(0 == (num_entries & (num_entries - 1)));
284
285
    /* Ensure remaining buffer is large enough to hold given number of entries */
286
18.6k
    ASSERT((num_entries * entry_size) <= buf_size);
287
288
18.6k
    ps_list->pv_buf_base = pu1_buf;
289
18.6k
    ps_list->i4_terminate = 0;
290
18.6k
    ps_list->i4_entry_size = entry_size;
291
18.6k
    ps_list->i4_buf_rd_idx = 0;
292
18.6k
    ps_list->i4_buf_wr_idx = 0;
293
18.6k
    ps_list->i4_log2_buf_max_idx = 32 - CLZ(num_entries);
294
18.6k
    ps_list->i4_buf_max_idx = num_entries;
295
18.6k
    ps_list->i4_yield_interval_us = yield_interval_us;
296
297
18.6k
    return ps_list;
298
18.6k
}
299
300
/**
301
*******************************************************************************
302
*
303
* @brief Resets the list context
304
*
305
* @par Description
306
*  Resets the list context by initializing buf queue context elements
307
*
308
* @param[in] ps_list
309
*  Pointer to job queue context
310
*
311
* @returns IH264_FAIL if lock unlock fails else IH264_SUCCESS
312
*
313
* @remarks
314
*
315
*******************************************************************************
316
*/
317
IH264_ERROR_T ih264_list_reset(list_t *ps_list)
318
227k
{
319
227k
    IH264_ERROR_T ret = IH264_SUCCESS;
320
321
227k
    ret = ih264_list_lock(ps_list);
322
227k
    RETURN_IF((ret != IH264_SUCCESS), ret);
323
324
227k
    ps_list->i4_terminate  = 0;
325
227k
    ps_list->i4_buf_rd_idx = 0;
326
227k
    ps_list->i4_buf_wr_idx = 0;
327
328
227k
    ret = ih264_list_unlock(ps_list);
329
227k
    RETURN_IF((ret != IH264_SUCCESS), ret);
330
331
227k
    return ret;
332
227k
}
333
334
/**
335
*******************************************************************************
336
*
337
* @brief De-initializes the list context
338
*
339
* @par Description
340
*  De-initializes the list context by calling ih264_list_reset() and then
341
*  destroying the mutex created
342
*
343
* @param[in] ps_list
344
*  Pointer to job queue context
345
*
346
* @returns IH264_FAIL if lock unlock fails else IH264_SUCCESS
347
*
348
* @remarks
349
*
350
*******************************************************************************
351
*/
352
IH264_ERROR_T ih264_list_deinit(list_t *ps_list)
353
0
{
354
0
    WORD32 retval;
355
0
    IH264_ERROR_T ret = IH264_SUCCESS;
356
357
0
    ret = ih264_list_reset(ps_list);
358
0
    RETURN_IF((ret != IH264_SUCCESS), ret);
359
360
0
    retval = ithread_mutex_destroy(ps_list->pv_mutex);
361
0
    if(retval)
362
0
        return IH264_FAIL;
363
0
    return IH264_SUCCESS;
364
0
}
365
366
/**
367
*******************************************************************************
368
*
369
* @brief Terminates the list
370
*
371
* @par Description
372
*  Terminates the list by setting a flag in context.
373
*
374
* @param[in] ps_list
375
*  Pointer to job queue context
376
*
377
* @returns IH264_FAIL if lock unlock fails else IH264_SUCCESS
378
*
379
* @remarks
380
*
381
*******************************************************************************
382
*/
383
IH264_ERROR_T ih264_list_terminate(list_t *ps_list)
384
205k
{
385
205k
    IH264_ERROR_T ret = IH264_SUCCESS;
386
387
205k
    ret = ih264_list_lock(ps_list);
388
205k
    RETURN_IF((ret != IH264_SUCCESS), ret);
389
390
205k
    ps_list->i4_terminate = 1;
391
392
205k
    ret = ih264_list_unlock(ps_list);
393
205k
    RETURN_IF((ret != IH264_SUCCESS), ret);
394
205k
    return ret;
395
205k
}
396
397
/**
398
*******************************************************************************
399
*
400
* @brief Adds a job to the queue
401
*
402
* @par Description
403
*  Adds a buffer to the queue and updates write address to next location.
404
*
405
* @param[in] ps_list
406
*  Pointer to job queue context
407
*
408
* @param[in] pv_buf
409
*  Pointer to the location that contains details of the job to be added
410
*
411
* @param[in] blocking
412
*  To signal if the write is blocking or non-blocking.
413
*
414
* @returns IH264_SUCCESS on success and IH264_FAIL on fail
415
*
416
* @remarks
417
*  Job Queue buffer is assumed to be allocated to handle worst case number of
418
*  buffers. Wrap around is not supported
419
*
420
*******************************************************************************
421
*/
422
IH264_ERROR_T ih264_list_queue(list_t *ps_list, void *pv_buf, WORD32 blocking)
423
985k
{
424
985k
    IH264_ERROR_T ret = IH264_SUCCESS;
425
985k
    IH264_ERROR_T rettmp;
426
985k
    WORD32 diff;
427
985k
    void *pv_buf_wr;
428
985k
    volatile WORD32 *pi4_wr_idx, *pi4_rd_idx;
429
985k
    WORD32 buf_size = ps_list->i4_entry_size;
430
431
432
985k
    rettmp = ih264_list_lock(ps_list);
433
985k
    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
434
435
985k
    while(1)
436
985k
    {
437
        /* Ensure wr idx does not go beyond rd idx by more than number of entries
438
         */
439
985k
        pi4_wr_idx = &ps_list->i4_buf_wr_idx;
440
985k
        pi4_rd_idx = &ps_list->i4_buf_rd_idx;
441
985k
        diff = *pi4_wr_idx - *pi4_rd_idx;
442
443
985k
        if(diff < ps_list->i4_buf_max_idx)
444
985k
        {
445
985k
            WORD32 wr_idx;
446
985k
            wr_idx = ps_list->i4_buf_wr_idx & (ps_list->i4_buf_max_idx - 1);
447
985k
            pv_buf_wr = (UWORD8 *)ps_list->pv_buf_base + wr_idx * buf_size;
448
449
985k
            memcpy(pv_buf_wr, pv_buf, buf_size);
450
985k
            ps_list->i4_buf_wr_idx++;
451
985k
            break;
452
985k
        }
453
0
        else
454
0
        {
455
            /* wr is ahead, so wait for rd to consume */
456
0
            if(blocking)
457
0
            {
458
0
                ih264_list_yield(ps_list);
459
0
            }
460
0
            else
461
0
            {
462
0
                ret = IH264_FAIL;
463
0
                break;
464
0
            }
465
0
        }
466
985k
    }
467
985k
    ps_list->i4_terminate = 0;
468
469
985k
    rettmp = ih264_list_unlock(ps_list);
470
985k
    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
471
472
985k
    return ret;
473
985k
}
474
475
/**
476
*******************************************************************************
477
*
478
* @brief Gets next job from the job queue
479
*
480
* @par   Description
481
*  Gets next job from the job queue and updates rd address to next location.
482
*  If it is a blocking call and if there is no new buf then this functions
483
*  unlocks the mutex and calls yield and then locks it back and continues
484
*  till a buf is available or terminate is set
485
*
486
* @param[in] ps_list
487
*  Pointer to Job Queue context
488
*
489
* @param[out] pv_buf
490
*  Pointer to the location that contains details of the buf to be written
491
*
492
* @param[in] blocking
493
*  To signal if the read is blocking or non-blocking.
494
*
495
* @returns
496
*
497
* @remarks
498
*  Job Queue buffer is assumed to be allocated to handle worst case number of
499
*  buffers. Wrap around is not supported
500
*
501
*******************************************************************************
502
*/
503
IH264_ERROR_T ih264_list_dequeue(list_t *ps_list, void *pv_buf, WORD32 blocking)
504
68.9M
{
505
68.9M
    IH264_ERROR_T ret = IH264_SUCCESS;
506
68.9M
    IH264_ERROR_T rettmp;
507
68.9M
    WORD32 buf_size = ps_list->i4_entry_size;
508
68.9M
    WORD32 diff;
509
68.9M
    void *pv_buf_rd;
510
68.9M
    volatile WORD32 *pi4_wr_idx, *pi4_rd_idx;
511
512
68.9M
    rettmp = ih264_list_lock(ps_list);
513
68.9M
    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
514
515
69.0M
    while(1)
516
69.1M
    {
517
        /* Ensure wr idx is ahead of rd idx and
518
         * wr idx does not go beyond rd idx by more than number of entries
519
         */
520
69.1M
        pi4_wr_idx = &ps_list->i4_buf_wr_idx;
521
69.1M
        pi4_rd_idx = &ps_list->i4_buf_rd_idx;
522
69.1M
        diff = *pi4_wr_idx - *pi4_rd_idx;
523
524
69.1M
        if(diff > 0)
525
977k
        {
526
977k
            WORD32 rd_idx;
527
977k
            rd_idx = ps_list->i4_buf_rd_idx & (ps_list->i4_buf_max_idx - 1);
528
977k
            pv_buf_rd = (UWORD8 *)ps_list->pv_buf_base + rd_idx * buf_size;
529
530
977k
            memcpy(pv_buf, pv_buf_rd, buf_size);
531
977k
            ps_list->i4_buf_rd_idx++;
532
977k
            break;
533
977k
        }
534
68.1M
        else
535
68.1M
        {
536
            /* If terminate is signaled then break */
537
68.1M
            if(ps_list->i4_terminate)
538
54.8M
            {
539
54.8M
                ret = IH264_FAIL;
540
54.8M
                break;
541
54.8M
            }
542
            /* wr is ahead, so wait for rd to consume */
543
13.2M
            if(blocking)
544
171k
            {
545
171k
                ih264_list_yield(ps_list);
546
171k
            }
547
13.0M
            else
548
13.0M
            {
549
13.0M
                ret = IH264_FAIL;
550
13.0M
                break;
551
13.0M
            }
552
13.2M
        }
553
69.1M
    }
554
555
68.9M
    rettmp = ih264_list_unlock(ps_list);
556
68.9M
    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
557
558
68.9M
    return ret;
559
68.9M
}
560
561
/**
562
*******************************************************************************
563
*
564
* @brief
565
*   Gets the number of jobs
566
*
567
* @par   Description
568
*   Gets the number of jobs to be processed in job queue context.
569
*
570
* @param[in] ps_list
571
*   Job Queue context
572
*
573
* @returns 0 if lock unlock fails else number of jobs to be processed
574
*
575
* @remarks
576
*
577
*******************************************************************************
578
*/
579
WORD32 ih264_get_job_count_in_list(list_t *ps_list)
580
12.2M
{
581
12.2M
    WORD32 jobs = 0;
582
12.2M
    RETURN_IF((ih264_list_lock(ps_list) != IH264_SUCCESS), 0);
583
12.2M
    jobs = ps_list->i4_buf_wr_idx - ps_list->i4_buf_rd_idx;
584
12.2M
    RETURN_IF((ih264_list_unlock(ps_list) != IH264_SUCCESS), 0);
585
12.2M
    return jobs;
586
12.2M
}