Coverage Report

Created: 2025-07-11 06:23

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