Coverage Report

Created: 2025-07-12 07:16

/src/libhevc/decoder/ihevcd_job_queue.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
*
3
* Copyright (C) 2012 Ittiam Systems Pvt Ltd, Bangalore
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
/**
19
*******************************************************************************
20
* @file
21
*  ihevcd_job_queue.c
22
*
23
* @brief
24
*  Contains functions for job queue
25
*
26
* @author
27
*  Harish
28
*
29
* @par List of Functions:
30
*
31
* @remarks
32
*  None
33
*
34
*******************************************************************************
35
*/
36
/*****************************************************************************/
37
/* File Includes                                                             */
38
/*****************************************************************************/
39
#include <stdio.h>
40
#include <stddef.h>
41
#include <stdlib.h>
42
#include <string.h>
43
#include <assert.h>
44
45
#include "ihevc_typedefs.h"
46
#include "iv.h"
47
#include "ivd.h"
48
#include "ihevcd_cxa.h"
49
#include "ithread.h"
50
#include "ihevc_platform_macros.h"
51
52
#include "ihevc_macros.h"
53
#include "ihevcd_error.h"
54
#include "ihevcd_job_queue.h"
55
56
/**
57
*******************************************************************************
58
*
59
* @brief Returns size for job queue context. Does not include job queue buffer
60
* requirements
61
*
62
* @par   Description
63
* Returns size for job queue context. Does not include job queue buffer
64
* requirements. Buffer size required to store the jobs should be allocated in
65
* addition to the value returned here.
66
*
67
* @returns Size of the job queue context
68
*
69
* @remarks
70
*
71
*******************************************************************************
72
*/
73
WORD32 ihevcd_jobq_ctxt_size()
74
2.20k
{
75
2.20k
    WORD32 size;
76
2.20k
    size = sizeof(jobq_t);
77
2.20k
    size += ithread_get_mutex_lock_size();
78
2.20k
    return size;
79
2.20k
}
80
81
/**
82
*******************************************************************************
83
*
84
* @brief
85
*   Locks the jobq conext
86
*
87
* @par   Description
88
*   Locks the jobq conext by calling ithread_mutex_lock()
89
*
90
* @param[in] ps_jobq
91
*   Job Queue context
92
*
93
* @returns IHEVCD_FAIL if mutex lock fails else IHEVCD_SUCCESS
94
*
95
* @remarks
96
*
97
*******************************************************************************
98
*/
99
IHEVCD_ERROR_T ihevcd_jobq_lock(jobq_t *ps_jobq)
100
602k
{
101
602k
    WORD32 retval;
102
602k
    retval = ithread_mutex_lock(ps_jobq->pv_mutex);
103
602k
    if(retval)
104
0
    {
105
0
        return (IHEVCD_ERROR_T)IHEVCD_FAIL;
106
0
    }
107
602k
    return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
108
602k
}
109
110
/**
111
*******************************************************************************
112
*
113
* @brief
114
*   Unlocks the jobq conext
115
*
116
* @par   Description
117
*   Unlocks the jobq conext by calling ithread_mutex_unlock()
118
*
119
* @param[in] ps_jobq
120
*   Job Queue context
121
*
122
* @returns IHEVCD_FAIL if mutex unlock fails else IHEVCD_SUCCESS
123
*
124
* @remarks
125
*
126
*******************************************************************************
127
*/
128
129
IHEVCD_ERROR_T ihevcd_jobq_unlock(jobq_t *ps_jobq)
130
603k
{
131
603k
    WORD32 retval;
132
603k
    retval = ithread_mutex_unlock(ps_jobq->pv_mutex);
133
603k
    if(retval)
134
0
    {
135
0
        return (IHEVCD_ERROR_T)IHEVCD_FAIL;
136
0
    }
137
603k
    return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
138
139
603k
}
140
/**
141
*******************************************************************************
142
*
143
* @brief
144
*   Yeilds the thread
145
*
146
* @par   Description
147
*   Unlocks the jobq conext by calling
148
* ihevcd_jobq_unlock(), ithread_yield() and then ihevcd_jobq_lock()
149
* jobq is unlocked before to ensure the jobq can be accessed by other threads
150
* If unlock is not done before calling yield then no other thread can access
151
* the jobq functions and update jobq.
152
*
153
* @param[in] ps_jobq
154
*   Job Queue context
155
*
156
* @returns IHEVCD_FAIL if mutex lock unlock or yield fails else IHEVCD_SUCCESS
157
*
158
* @remarks
159
*
160
*******************************************************************************
161
*/
162
IHEVCD_ERROR_T ihevcd_jobq_yield(jobq_t *ps_jobq)
163
289k
{
164
165
289k
    IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
166
167
289k
    IHEVCD_ERROR_T rettmp;
168
289k
    rettmp = ihevcd_jobq_unlock(ps_jobq);
169
289k
    RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
170
171
    //NOP(1024 * 8);
172
289k
    ithread_yield();
173
174
289k
    rettmp = ihevcd_jobq_lock(ps_jobq);
175
289k
    RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
176
289k
    return ret;
177
289k
}
178
179
180
/**
181
*******************************************************************************
182
*
183
* @brief free the job queue pointers
184
*
185
* @par   Description
186
* Frees the jobq context
187
*
188
* @param[in] pv_buf
189
* Memoy for job queue buffer and job queue context
190
*
191
* @returns Pointer to job queue context
192
*
193
* @remarks
194
* Since it will be called only once by master thread this is not thread safe.
195
*
196
*******************************************************************************
197
*/
198
IHEVCD_ERROR_T ihevcd_jobq_free(jobq_t *ps_jobq)
199
0
{
200
0
    WORD32 ret;
201
0
    ret = ithread_mutex_destroy(ps_jobq->pv_mutex);
202
203
0
    if(0 == ret)
204
0
        return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
205
0
    else
206
0
        return (IHEVCD_ERROR_T)IHEVCD_FAIL;
207
0
}
208
209
/**
210
*******************************************************************************
211
*
212
* @brief Initialize the job queue
213
*
214
* @par   Description
215
* Initializes the jobq context and sets write and read pointers to start of
216
* job queue buffer
217
*
218
* @param[in] pv_buf
219
* Memoy for job queue buffer and job queue context
220
*
221
* @param[in] buf_size
222
* Size of the total memory allocated
223
*
224
* @returns Pointer to job queue context
225
*
226
* @remarks
227
* Since it will be called only once by master thread this is not thread safe.
228
*
229
*******************************************************************************
230
*/
231
void* ihevcd_jobq_init(void *pv_buf, WORD32 buf_size)
232
2.20k
{
233
2.20k
    jobq_t *ps_jobq;
234
2.20k
    UWORD8 *pu1_buf;
235
2.20k
    pu1_buf = (UWORD8 *)pv_buf;
236
237
2.20k
    ps_jobq = (jobq_t *)pu1_buf;
238
2.20k
    pu1_buf += sizeof(jobq_t);
239
2.20k
    buf_size -= sizeof(jobq_t);
240
241
2.20k
    ps_jobq->pv_mutex = pu1_buf;
242
2.20k
    pu1_buf += ithread_get_mutex_lock_size();
243
2.20k
    buf_size -= ithread_get_mutex_lock_size();
244
245
2.20k
    if(buf_size <= 0)
246
0
        return NULL;
247
248
2.20k
    ithread_mutex_init(ps_jobq->pv_mutex);
249
250
2.20k
    ps_jobq->pv_buf_base = pu1_buf;
251
2.20k
    ps_jobq->pv_buf_wr = pu1_buf;
252
2.20k
    ps_jobq->pv_buf_rd = pu1_buf;
253
2.20k
    ps_jobq->pv_buf_end = pu1_buf + buf_size;
254
2.20k
    ps_jobq->i4_terminate = 0;
255
256
257
2.20k
    return ps_jobq;
258
2.20k
}
259
/**
260
*******************************************************************************
261
*
262
* @brief
263
*   Resets the jobq conext
264
*
265
* @par   Description
266
*   Resets the jobq conext by initilizing job queue context elements
267
*
268
* @param[in] ps_jobq
269
*   Job Queue context
270
*
271
* @returns IHEVCD_FAIL if lock unlock fails else IHEVCD_SUCCESS
272
*
273
* @remarks
274
*
275
*******************************************************************************
276
*/
277
IHEVCD_ERROR_T ihevcd_jobq_reset(jobq_t *ps_jobq)
278
11.7k
{
279
11.7k
    IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
280
11.7k
    ret = ihevcd_jobq_lock(ps_jobq);
281
11.7k
    RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
282
283
11.7k
    ps_jobq->pv_buf_wr      = ps_jobq->pv_buf_base;
284
11.7k
    ps_jobq->pv_buf_rd      = ps_jobq->pv_buf_base;
285
11.7k
    ps_jobq->i4_terminate   = 0;
286
11.7k
    ret = ihevcd_jobq_unlock(ps_jobq);
287
11.7k
    RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
288
289
11.7k
    return ret;
290
11.7k
}
291
292
/**
293
*******************************************************************************
294
*
295
* @brief
296
*   Deinitializes the jobq conext
297
*
298
* @par   Description
299
*   Deinitializes the jobq conext by calling ihevc_jobq_reset()
300
* and then destrying the mutex created
301
*
302
* @param[in] ps_jobq
303
*   Job Queue context
304
*
305
* @returns IHEVCD_FAIL if lock unlock fails else IHEVCD_SUCCESS
306
*
307
* @remarks
308
*
309
*******************************************************************************
310
*/
311
IHEVCD_ERROR_T ihevcd_jobq_deinit(jobq_t *ps_jobq)
312
2.20k
{
313
2.20k
    WORD32 retval;
314
2.20k
    IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
315
316
2.20k
    ret = ihevcd_jobq_reset(ps_jobq);
317
2.20k
    RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
318
319
2.20k
    retval = ithread_mutex_destroy(ps_jobq->pv_mutex);
320
2.20k
    if(retval)
321
0
    {
322
0
        return (IHEVCD_ERROR_T)IHEVCD_FAIL;
323
0
    }
324
325
2.20k
    return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
326
2.20k
}
327
328
329
/**
330
*******************************************************************************
331
*
332
* @brief
333
*   Terminates the jobq
334
*
335
* @par   Description
336
*   Terminates the jobq by setting a flag in context.
337
*
338
* @param[in] ps_jobq
339
*   Job Queue context
340
*
341
* @returns IHEVCD_FAIL if lock unlock fails else IHEVCD_SUCCESS
342
*
343
* @remarks
344
*
345
*******************************************************************************
346
*/
347
348
IHEVCD_ERROR_T ihevcd_jobq_terminate(jobq_t *ps_jobq)
349
3.95k
{
350
3.95k
    IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
351
3.95k
    ret = ihevcd_jobq_lock(ps_jobq);
352
3.95k
    RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
353
354
3.95k
    ps_jobq->i4_terminate = 1;
355
356
3.95k
    ret = ihevcd_jobq_unlock(ps_jobq);
357
3.95k
    RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
358
3.95k
    return ret;
359
3.95k
}
360
361
362
/**
363
*******************************************************************************
364
*
365
* @brief Adds a job to the queue
366
*
367
* @par   Description
368
* Adds a job to the queue and updates wr address to next location.
369
* Format/content of the job structure is abstracted and hence size of the job
370
* buffer is being passed.
371
*
372
* @param[in] ps_jobq
373
*   Job Queue context
374
*
375
* @param[in] pv_job
376
*   Pointer to the location that contains details of the job to be added
377
*
378
* @param[in] job_size
379
*   Size of the job buffer
380
*
381
* @param[in] blocking
382
*   To signal if the write is blocking or non-blocking.
383
*
384
* @returns
385
*
386
* @remarks
387
* Job Queue buffer is assumed to be allocated to handle worst case number of jobs
388
* Wrap around is not supported
389
*
390
*******************************************************************************
391
*/
392
IHEVCD_ERROR_T ihevcd_jobq_queue(jobq_t *ps_jobq, void *pv_job, WORD32 job_size, WORD32 blocking)
393
143k
{
394
143k
    IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
395
143k
    IHEVCD_ERROR_T rettmp;
396
143k
    UWORD8 *pu1_buf;
397
143k
    UNUSED(blocking);
398
399
143k
    rettmp = ihevcd_jobq_lock(ps_jobq);
400
143k
    RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
401
402
143k
    pu1_buf = (UWORD8 *)ps_jobq->pv_buf_wr;
403
143k
    if((UWORD8 *)ps_jobq->pv_buf_end >= (pu1_buf + job_size))
404
143k
    {
405
143k
        memcpy(ps_jobq->pv_buf_wr, pv_job, job_size);
406
143k
        ps_jobq->pv_buf_wr = (UWORD8 *)ps_jobq->pv_buf_wr + job_size;
407
143k
        ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
408
143k
    }
409
0
    else
410
0
    {
411
        /* Handle wrap around case */
412
        /* Wait for pv_buf_rd to consume first job_size number of bytes
413
         * from the beginning of job queue
414
         */
415
0
        ret = (IHEVCD_ERROR_T)IHEVCD_FAIL;
416
0
    }
417
418
143k
    ps_jobq->i4_terminate = 0;
419
420
143k
    rettmp = ihevcd_jobq_unlock(ps_jobq);
421
143k
    RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
422
423
143k
    return ret;
424
143k
}
425
/**
426
*******************************************************************************
427
*
428
* @brief Gets next from the Job queue
429
*
430
* @par   Description
431
* Gets next job from the job queue and updates rd address to next location.
432
* Format/content of the job structure is abstracted and hence size of the job
433
* buffer is being passed. If it is a blocking call and if there is no new job
434
* then this functions unlocks the mutext and calls yield and then locks it back.
435
* and continues till a job is available or terminate is set
436
*
437
* @param[in] ps_jobq
438
*   Job Queue context
439
*
440
* @param[out] pv_job
441
*   Pointer to the location that contains details of the job to be written
442
*
443
* @param[in] job_size
444
*   Size of the job buffer
445
*
446
* @param[in] blocking
447
*   To signal if the read is blocking or non-blocking.
448
*
449
* @returns
450
*
451
* @remarks
452
* Job Queue buffer is assumed to be allocated to handle worst case number of jobs
453
* Wrap around is not supported
454
*
455
*******************************************************************************
456
*/
457
IHEVCD_ERROR_T ihevcd_jobq_dequeue(jobq_t *ps_jobq, void *pv_job, WORD32 job_size, WORD32 blocking)
458
153k
{
459
153k
    IHEVCD_ERROR_T ret;
460
153k
    IHEVCD_ERROR_T rettmp;
461
153k
    volatile UWORD8 *pu1_buf;
462
463
153k
    rettmp = ihevcd_jobq_lock(ps_jobq);
464
153k
    RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
465
153k
    pu1_buf = (UWORD8 *)ps_jobq->pv_buf_rd;
466
467
468
153k
    if((UWORD8 *)ps_jobq->pv_buf_end >= (pu1_buf + job_size))
469
154k
    {
470
444k
        while(1)
471
444k
        {
472
444k
            pu1_buf = (UWORD8 *)ps_jobq->pv_buf_rd;
473
444k
            if((UWORD8 *)ps_jobq->pv_buf_wr >= (pu1_buf + job_size))
474
143k
            {
475
143k
                memcpy(pv_job, ps_jobq->pv_buf_rd, job_size);
476
143k
                ps_jobq->pv_buf_rd = (UWORD8 *)ps_jobq->pv_buf_rd + job_size;
477
143k
                ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
478
143k
                break;
479
143k
            }
480
300k
            else
481
300k
            {
482
                /* If all the entries have been dequeued, then break and return */
483
300k
                if(1 == ps_jobq->i4_terminate)
484
10.7k
                {
485
10.7k
                    ret = (IHEVCD_ERROR_T)IHEVCD_FAIL;
486
10.7k
                    break;
487
10.7k
                }
488
489
289k
                if(1 == blocking)
490
289k
                {
491
289k
                    ihevcd_jobq_yield(ps_jobq);
492
493
289k
                }
494
0
                else
495
0
                {
496
                    /* If there is no job available,
497
                     * and this is non blocking call then return fail */
498
0
                    ret = (IHEVCD_ERROR_T)IHEVCD_FAIL;
499
0
                }
500
289k
            }
501
444k
        }
502
154k
    }
503
18.4E
    else
504
18.4E
    {
505
        /* Handle wrap around case */
506
        /* Wait for pv_buf_rd to consume first job_size number of bytes
507
         * from the beginning of job queue
508
         */
509
18.4E
        ret = (IHEVCD_ERROR_T)IHEVCD_FAIL;
510
18.4E
    }
511
153k
    rettmp = ihevcd_jobq_unlock(ps_jobq);
512
153k
    RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
513
514
153k
    return ret;
515
153k
}