Coverage Report

Created: 2026-02-14 06:46

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
31.1k
{
97
31.1k
    WORD32 size;
98
31.1k
    WORD32 clz;
99
100
31.1k
    size = sizeof(list_t);
101
31.1k
    size += ithread_get_mutex_lock_size();
102
103
    /* Use next power of two number of entries*/
104
31.1k
    clz = CLZ(num_entries);
105
31.1k
    num_entries = 1 << (32 - clz);
106
107
31.1k
    size += num_entries * entry_size;
108
31.1k
    return size;
109
31.1k
}
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
81.9M
{
130
81.9M
    WORD32 retval;
131
132
81.9M
    retval = ithread_mutex_lock(ps_list->pv_mutex);
133
81.9M
    if(retval)
134
0
        return IH264_FAIL;
135
81.9M
    return IH264_SUCCESS;
136
81.9M
}
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
81.9M
{
157
81.9M
    WORD32 retval;
158
159
81.9M
    retval = ithread_mutex_unlock(ps_list->pv_mutex);
160
81.9M
    if(retval)
161
0
        return IH264_FAIL;
162
81.9M
    return IH264_SUCCESS;
163
81.9M
}
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
177k
{
187
177k
    IH264_ERROR_T ret;
188
189
177k
    ret = ih264_list_unlock(ps_list);
190
177k
    RETURN_IF((ret != IH264_SUCCESS), ret);
191
192
177k
    ithread_yield();
193
194
177k
    if(ps_list->i4_yield_interval_us > 0)
195
177k
        ithread_usleep(ps_list->i4_yield_interval_us);
196
197
177k
    ret = ih264_list_lock(ps_list);
198
177k
    RETURN_IF((ret != IH264_SUCCESS), ret);
199
177k
    return IH264_SUCCESS;
200
177k
}
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
7.17k
{
222
7.17k
    WORD32 ret;
223
224
7.17k
    ret = ithread_mutex_destroy(ps_list->pv_mutex);
225
7.17k
    if(0 == ret)
226
7.17k
        return IH264_SUCCESS;
227
0
    return IH264_FAIL;
228
7.17k
}
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
15.5k
{
267
15.5k
    list_t *ps_list = (list_t *)pv_buf;
268
15.5k
    UWORD8 *pu1_buf = (UWORD8 *)pv_buf;
269
270
15.5k
    pu1_buf += sizeof(list_t);
271
15.5k
    buf_size -= sizeof(list_t);
272
273
15.5k
    ps_list->pv_mutex = pu1_buf;
274
15.5k
    pu1_buf += ithread_get_mutex_lock_size();
275
15.5k
    buf_size -= ithread_get_mutex_lock_size();
276
277
15.5k
    if (buf_size <= 0)
278
0
      return NULL;
279
280
15.5k
    ithread_mutex_init(ps_list->pv_mutex);
281
282
    /* Ensure num_entries is power of two */
283
15.5k
    ASSERT(0 == (num_entries & (num_entries - 1)));
284
285
    /* Ensure remaining buffer is large enough to hold given number of entries */
286
15.5k
    ASSERT((num_entries * entry_size) <= buf_size);
287
288
15.5k
    ps_list->pv_buf_base = pu1_buf;
289
15.5k
    ps_list->i4_terminate = 0;
290
15.5k
    ps_list->i4_entry_size = entry_size;
291
15.5k
    ps_list->i4_buf_rd_idx = 0;
292
15.5k
    ps_list->i4_buf_wr_idx = 0;
293
15.5k
    ps_list->i4_log2_buf_max_idx = 32 - CLZ(num_entries);
294
15.5k
    ps_list->i4_buf_max_idx = num_entries;
295
15.5k
    ps_list->i4_yield_interval_us = yield_interval_us;
296
297
15.5k
    return ps_list;
298
15.5k
}
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
197k
{
319
197k
    IH264_ERROR_T ret = IH264_SUCCESS;
320
321
197k
    ret = ih264_list_lock(ps_list);
322
197k
    RETURN_IF((ret != IH264_SUCCESS), ret);
323
324
197k
    ps_list->i4_terminate  = 0;
325
197k
    ps_list->i4_buf_rd_idx = 0;
326
197k
    ps_list->i4_buf_wr_idx = 0;
327
328
197k
    ret = ih264_list_unlock(ps_list);
329
197k
    RETURN_IF((ret != IH264_SUCCESS), ret);
330
331
197k
    return ret;
332
197k
}
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
178k
{
385
178k
    IH264_ERROR_T ret = IH264_SUCCESS;
386
387
178k
    ret = ih264_list_lock(ps_list);
388
178k
    RETURN_IF((ret != IH264_SUCCESS), ret);
389
390
178k
    ps_list->i4_terminate = 1;
391
392
178k
    ret = ih264_list_unlock(ps_list);
393
178k
    RETURN_IF((ret != IH264_SUCCESS), ret);
394
178k
    return ret;
395
178k
}
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
832k
{
424
832k
    IH264_ERROR_T ret = IH264_SUCCESS;
425
832k
    IH264_ERROR_T rettmp;
426
832k
    WORD32 diff;
427
832k
    void *pv_buf_wr;
428
832k
    volatile WORD32 *pi4_wr_idx, *pi4_rd_idx;
429
832k
    WORD32 buf_size = ps_list->i4_entry_size;
430
431
432
832k
    rettmp = ih264_list_lock(ps_list);
433
832k
    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
434
435
832k
    while(1)
436
832k
    {
437
        /* Ensure wr idx does not go beyond rd idx by more than number of entries
438
         */
439
832k
        pi4_wr_idx = &ps_list->i4_buf_wr_idx;
440
832k
        pi4_rd_idx = &ps_list->i4_buf_rd_idx;
441
832k
        diff = *pi4_wr_idx - *pi4_rd_idx;
442
443
832k
        if(diff < ps_list->i4_buf_max_idx)
444
832k
        {
445
832k
            WORD32 wr_idx;
446
832k
            wr_idx = ps_list->i4_buf_wr_idx & (ps_list->i4_buf_max_idx - 1);
447
832k
            pv_buf_wr = (UWORD8 *)ps_list->pv_buf_base + wr_idx * buf_size;
448
449
832k
            memcpy(pv_buf_wr, pv_buf, buf_size);
450
832k
            ps_list->i4_buf_wr_idx++;
451
832k
            break;
452
832k
        }
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
832k
    }
467
832k
    ps_list->i4_terminate = 0;
468
469
832k
    rettmp = ih264_list_unlock(ps_list);
470
832k
    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
471
472
832k
    return ret;
473
832k
}
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.0M
{
505
68.0M
    IH264_ERROR_T ret = IH264_SUCCESS;
506
68.0M
    IH264_ERROR_T rettmp;
507
68.0M
    WORD32 buf_size = ps_list->i4_entry_size;
508
68.0M
    WORD32 diff;
509
68.0M
    void *pv_buf_rd;
510
68.0M
    volatile WORD32 *pi4_wr_idx, *pi4_rd_idx;
511
512
68.0M
    rettmp = ih264_list_lock(ps_list);
513
68.0M
    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
514
515
68.2M
    while(1)
516
68.2M
    {
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
68.2M
        pi4_wr_idx = &ps_list->i4_buf_wr_idx;
521
68.2M
        pi4_rd_idx = &ps_list->i4_buf_rd_idx;
522
68.2M
        diff = *pi4_wr_idx - *pi4_rd_idx;
523
524
68.2M
        if(diff > 0)
525
824k
        {
526
824k
            WORD32 rd_idx;
527
824k
            rd_idx = ps_list->i4_buf_rd_idx & (ps_list->i4_buf_max_idx - 1);
528
824k
            pv_buf_rd = (UWORD8 *)ps_list->pv_buf_base + rd_idx * buf_size;
529
530
824k
            memcpy(pv_buf, pv_buf_rd, buf_size);
531
824k
            ps_list->i4_buf_rd_idx++;
532
824k
            break;
533
824k
        }
534
67.4M
        else
535
67.4M
        {
536
            /* If terminate is signaled then break */
537
67.4M
            if(ps_list->i4_terminate)
538
53.4M
            {
539
53.4M
                ret = IH264_FAIL;
540
53.4M
                break;
541
53.4M
            }
542
            /* wr is ahead, so wait for rd to consume */
543
14.0M
            if(blocking)
544
177k
            {
545
177k
                ih264_list_yield(ps_list);
546
177k
            }
547
13.8M
            else
548
13.8M
            {
549
13.8M
                ret = IH264_FAIL;
550
13.8M
                break;
551
13.8M
            }
552
14.0M
        }
553
68.2M
    }
554
555
68.0M
    rettmp = ih264_list_unlock(ps_list);
556
68.0M
    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);
557
558
68.0M
    return ret;
559
68.0M
}
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.4M
{
581
12.4M
    WORD32 jobs = 0;
582
12.4M
    RETURN_IF((ih264_list_lock(ps_list) != IH264_SUCCESS), 0);
583
12.4M
    jobs = ps_list->i4_buf_wr_idx - ps_list->i4_buf_rd_idx;
584
12.4M
    RETURN_IF((ih264_list_unlock(ps_list) != IH264_SUCCESS), 0);
585
12.4M
    return jobs;
586
12.4M
}