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 */
impeg2_jobq_ctxt_size()70 WORD32 impeg2_jobq_ctxt_size()
71 {
72 WORD32 i4_size;
73 i4_size = sizeof(jobq_t);
74 i4_size += ithread_get_mutex_lock_size();
75 return i4_size;
76 }
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 */
impeg2_jobq_lock(jobq_t * ps_jobq)96 IV_API_CALL_STATUS_T impeg2_jobq_lock(jobq_t *ps_jobq)
97 {
98 WORD32 i4_ret_val;
99 i4_ret_val = ithread_mutex_lock(ps_jobq->pv_mutex);
100 if(i4_ret_val)
101 {
102 return IV_FAIL;
103 }
104 return IV_SUCCESS;
105 }
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
impeg2_jobq_unlock(jobq_t * ps_jobq)126 IV_API_CALL_STATUS_T impeg2_jobq_unlock(jobq_t *ps_jobq)
127 {
128 WORD32 i4_ret_val;
129 i4_ret_val = ithread_mutex_unlock(ps_jobq->pv_mutex);
130 if(i4_ret_val)
131 {
132 return IV_FAIL;
133 }
134 return IV_SUCCESS;
135
136 }
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 */
impeg2_jobq_yield(jobq_t * ps_jobq)159 IV_API_CALL_STATUS_T impeg2_jobq_yield(jobq_t *ps_jobq)
160 {
161
162 IV_API_CALL_STATUS_T e_ret = IV_SUCCESS;
163
164 IV_API_CALL_STATUS_T e_ret_tmp;
165 e_ret_tmp = impeg2_jobq_unlock(ps_jobq);
166 RETURN_IF((e_ret_tmp != IV_SUCCESS), e_ret_tmp);
167
168 //NOP(1024 * 8);
169 ithread_yield();
170
171 e_ret_tmp = impeg2_jobq_lock(ps_jobq);
172 RETURN_IF((e_ret_tmp != IV_SUCCESS), e_ret_tmp);
173 return e_ret;
174 }
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 */
impeg2_jobq_free(jobq_t * ps_jobq)195 IV_API_CALL_STATUS_T impeg2_jobq_free(jobq_t *ps_jobq)
196 {
197 WORD32 i4_ret;
198 i4_ret = ithread_mutex_destroy(ps_jobq->pv_mutex);
199
200 if(0 == i4_ret)
201 return IV_SUCCESS;
202 else
203 return IV_FAIL;
204 }
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 */
impeg2_jobq_init(void * pv_buf,WORD32 i4_buf_size)228 void* impeg2_jobq_init(void *pv_buf, WORD32 i4_buf_size)
229 {
230 jobq_t *ps_jobq;
231 UWORD8 *pu1_buf;
232 pu1_buf = (UWORD8 *)pv_buf;
233
234 ps_jobq = (jobq_t *)pu1_buf;
235 pu1_buf += sizeof(jobq_t);
236 i4_buf_size -= sizeof(jobq_t);
237
238 ps_jobq->pv_mutex = pu1_buf;
239 pu1_buf += ithread_get_mutex_lock_size();
240 i4_buf_size -= ithread_get_mutex_lock_size();
241
242 if(i4_buf_size <= 0)
243 return NULL;
244
245 ithread_mutex_init(ps_jobq->pv_mutex);
246
247 ps_jobq->pv_buf_base = pu1_buf;
248 ps_jobq->pv_buf_wr = pu1_buf;
249 ps_jobq->pv_buf_rd = pu1_buf;
250 ps_jobq->pv_buf_end = pu1_buf + i4_buf_size;
251 ps_jobq->i4_terminate = 0;
252
253
254 return ps_jobq;
255 }
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 */
impeg2_jobq_reset(jobq_t * ps_jobq)274 IV_API_CALL_STATUS_T impeg2_jobq_reset(jobq_t *ps_jobq)
275 {
276 IV_API_CALL_STATUS_T e_ret = IV_SUCCESS;
277 e_ret = impeg2_jobq_lock(ps_jobq);
278 RETURN_IF((e_ret != IV_SUCCESS), e_ret);
279
280 ps_jobq->pv_buf_wr = ps_jobq->pv_buf_base;
281 ps_jobq->pv_buf_rd = ps_jobq->pv_buf_base;
282 ps_jobq->i4_terminate = 0;
283 e_ret = impeg2_jobq_unlock(ps_jobq);
284 RETURN_IF((e_ret != IV_SUCCESS), e_ret);
285
286 return e_ret;
287 }
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 */
impeg2_jobq_deinit(jobq_t * ps_jobq)308 IV_API_CALL_STATUS_T impeg2_jobq_deinit(jobq_t *ps_jobq)
309 {
310 WORD32 i4_ret_val;
311 IV_API_CALL_STATUS_T e_ret = IV_SUCCESS;
312
313 e_ret = impeg2_jobq_reset(ps_jobq);
314 RETURN_IF((e_ret != IV_SUCCESS), e_ret);
315
316 i4_ret_val = ithread_mutex_destroy(ps_jobq->pv_mutex);
317 if(i4_ret_val)
318 {
319 return IV_FAIL;
320 }
321
322 return IV_SUCCESS;
323 }
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
impeg2_jobq_terminate(jobq_t * ps_jobq)345 IV_API_CALL_STATUS_T impeg2_jobq_terminate(jobq_t *ps_jobq)
346 {
347 IV_API_CALL_STATUS_T e_ret = IV_SUCCESS;
348 e_ret = impeg2_jobq_lock(ps_jobq);
349 RETURN_IF((e_ret != IV_SUCCESS), e_ret);
350
351 ps_jobq->i4_terminate = 1;
352
353 e_ret = impeg2_jobq_unlock(ps_jobq);
354 RETURN_IF((e_ret != IV_SUCCESS), e_ret);
355 return e_ret;
356 }
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 */
impeg2_jobq_queue(jobq_t * ps_jobq,void * pv_job,WORD32 i4_job_size,WORD32 i4_blocking,WORD32 i4_lock)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 {
395 IV_API_CALL_STATUS_T e_ret = IV_SUCCESS;
396 IV_API_CALL_STATUS_T e_ret_tmp;
397 UWORD8 *pu1_buf;
398 UNUSED(i4_blocking);
399
400 if(i4_lock)
401 {
402 e_ret_tmp = impeg2_jobq_lock(ps_jobq);
403 RETURN_IF((e_ret_tmp != IV_SUCCESS), e_ret_tmp);
404 }
405 pu1_buf = (UWORD8 *)ps_jobq->pv_buf_wr;
406 if((UWORD8 *)ps_jobq->pv_buf_end >= (pu1_buf + i4_job_size))
407 {
408 memcpy(ps_jobq->pv_buf_wr, pv_job, i4_job_size);
409 ps_jobq->pv_buf_wr = (UWORD8 *)ps_jobq->pv_buf_wr + i4_job_size;
410 e_ret = IV_SUCCESS;
411 }
412 else
413 {
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 e_ret = IV_FAIL;
419 }
420
421 ps_jobq->i4_terminate = 0;
422
423 if(i4_lock)
424 {
425 e_ret_tmp = impeg2_jobq_unlock(ps_jobq);
426 RETURN_IF((e_ret_tmp != IV_SUCCESS), e_ret_tmp);
427 }
428
429 return e_ret;
430 }
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 */
impeg2_jobq_dequeue(jobq_t * ps_jobq,void * pv_job,WORD32 i4_job_size,WORD32 i4_blocking,WORD32 i4_lock)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 {
469 IV_API_CALL_STATUS_T e_ret;
470 IV_API_CALL_STATUS_T e_ret_tmp;
471 volatile UWORD8 *pu1_buf;
472 if(i4_lock)
473 {
474 e_ret_tmp = impeg2_jobq_lock(ps_jobq);
475 RETURN_IF((e_ret_tmp != IV_SUCCESS), e_ret_tmp);
476 }
477 pu1_buf = (UWORD8 *)ps_jobq->pv_buf_rd;
478
479
480 if((UWORD8 *)ps_jobq->pv_buf_end >= (pu1_buf + i4_job_size))
481 {
482 while(1)
483 {
484 pu1_buf = (UWORD8 *)ps_jobq->pv_buf_rd;
485 if((UWORD8 *)ps_jobq->pv_buf_wr >= (pu1_buf + i4_job_size))
486 {
487 memcpy(pv_job, ps_jobq->pv_buf_rd, i4_job_size);
488 ps_jobq->pv_buf_rd = (UWORD8 *)ps_jobq->pv_buf_rd + i4_job_size;
489 e_ret = IV_SUCCESS;
490 break;
491 }
492 else
493 {
494 /* If all the entries have been dequeued, then break and return */
495 if(1 == ps_jobq->i4_terminate)
496 {
497 e_ret = IV_FAIL;
498 break;
499 }
500
501 if((1 == i4_blocking) && (1 == i4_lock))
502 {
503 impeg2_jobq_yield(ps_jobq);
504
505 }
506 else
507 {
508 /* If there is no job available,
509 * and this is non blocking call then return fail */
510 e_ret = IV_FAIL;
511 }
512 }
513 }
514 }
515 else
516 {
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 e_ret = IV_FAIL;
522 }
523 if(i4_lock)
524 {
525 e_ret_tmp = impeg2_jobq_unlock(ps_jobq);
526 RETURN_IF((e_ret_tmp != IV_SUCCESS), e_ret_tmp);
527 }
528
529 return e_ret;
530 }
531