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 */
ihevcd_jobq_ctxt_size()73 WORD32 ihevcd_jobq_ctxt_size()
74 {
75 WORD32 size;
76 size = sizeof(jobq_t);
77 size += ithread_get_mutex_lock_size();
78 return size;
79 }
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 */
ihevcd_jobq_lock(jobq_t * ps_jobq)99 IHEVCD_ERROR_T ihevcd_jobq_lock(jobq_t *ps_jobq)
100 {
101 WORD32 retval;
102 retval = ithread_mutex_lock(ps_jobq->pv_mutex);
103 if(retval)
104 {
105 return (IHEVCD_ERROR_T)IHEVCD_FAIL;
106 }
107 return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
108 }
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
ihevcd_jobq_unlock(jobq_t * ps_jobq)129 IHEVCD_ERROR_T ihevcd_jobq_unlock(jobq_t *ps_jobq)
130 {
131 WORD32 retval;
132 retval = ithread_mutex_unlock(ps_jobq->pv_mutex);
133 if(retval)
134 {
135 return (IHEVCD_ERROR_T)IHEVCD_FAIL;
136 }
137 return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
138
139 }
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 */
ihevcd_jobq_yield(jobq_t * ps_jobq)162 IHEVCD_ERROR_T ihevcd_jobq_yield(jobq_t *ps_jobq)
163 {
164
165 IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
166
167 IHEVCD_ERROR_T rettmp;
168 rettmp = ihevcd_jobq_unlock(ps_jobq);
169 RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
170
171 //NOP(1024 * 8);
172 ithread_yield();
173
174 rettmp = ihevcd_jobq_lock(ps_jobq);
175 RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
176 return ret;
177 }
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 */
ihevcd_jobq_free(jobq_t * ps_jobq)198 IHEVCD_ERROR_T ihevcd_jobq_free(jobq_t *ps_jobq)
199 {
200 WORD32 ret;
201 ret = ithread_mutex_destroy(ps_jobq->pv_mutex);
202
203 if(0 == ret)
204 return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
205 else
206 return (IHEVCD_ERROR_T)IHEVCD_FAIL;
207 }
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 */
ihevcd_jobq_init(void * pv_buf,WORD32 buf_size)231 void* ihevcd_jobq_init(void *pv_buf, WORD32 buf_size)
232 {
233 jobq_t *ps_jobq;
234 UWORD8 *pu1_buf;
235 pu1_buf = (UWORD8 *)pv_buf;
236
237 ps_jobq = (jobq_t *)pu1_buf;
238 pu1_buf += sizeof(jobq_t);
239 buf_size -= sizeof(jobq_t);
240
241 ps_jobq->pv_mutex = pu1_buf;
242 pu1_buf += ithread_get_mutex_lock_size();
243 buf_size -= ithread_get_mutex_lock_size();
244
245 if(buf_size <= 0)
246 return NULL;
247
248 ithread_mutex_init(ps_jobq->pv_mutex);
249
250 ps_jobq->pv_buf_base = pu1_buf;
251 ps_jobq->pv_buf_wr = pu1_buf;
252 ps_jobq->pv_buf_rd = pu1_buf;
253 ps_jobq->pv_buf_end = pu1_buf + buf_size;
254 ps_jobq->i4_terminate = 0;
255
256
257 return ps_jobq;
258 }
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 */
ihevcd_jobq_reset(jobq_t * ps_jobq)277 IHEVCD_ERROR_T ihevcd_jobq_reset(jobq_t *ps_jobq)
278 {
279 IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
280 ret = ihevcd_jobq_lock(ps_jobq);
281 RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
282
283 ps_jobq->pv_buf_wr = ps_jobq->pv_buf_base;
284 ps_jobq->pv_buf_rd = ps_jobq->pv_buf_base;
285 ps_jobq->i4_terminate = 0;
286 ret = ihevcd_jobq_unlock(ps_jobq);
287 RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
288
289 return ret;
290 }
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 */
ihevcd_jobq_deinit(jobq_t * ps_jobq)311 IHEVCD_ERROR_T ihevcd_jobq_deinit(jobq_t *ps_jobq)
312 {
313 WORD32 retval;
314 IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
315
316 ret = ihevcd_jobq_reset(ps_jobq);
317 RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
318
319 retval = ithread_mutex_destroy(ps_jobq->pv_mutex);
320 if(retval)
321 {
322 return (IHEVCD_ERROR_T)IHEVCD_FAIL;
323 }
324
325 return (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
326 }
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
ihevcd_jobq_terminate(jobq_t * ps_jobq)348 IHEVCD_ERROR_T ihevcd_jobq_terminate(jobq_t *ps_jobq)
349 {
350 IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
351 ret = ihevcd_jobq_lock(ps_jobq);
352 RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
353
354 ps_jobq->i4_terminate = 1;
355
356 ret = ihevcd_jobq_unlock(ps_jobq);
357 RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
358 return ret;
359 }
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 */
ihevcd_jobq_queue(jobq_t * ps_jobq,void * pv_job,WORD32 job_size,WORD32 blocking)392 IHEVCD_ERROR_T ihevcd_jobq_queue(jobq_t *ps_jobq, void *pv_job, WORD32 job_size, WORD32 blocking)
393 {
394 IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
395 IHEVCD_ERROR_T rettmp;
396 UWORD8 *pu1_buf;
397 UNUSED(blocking);
398
399 rettmp = ihevcd_jobq_lock(ps_jobq);
400 RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
401
402 pu1_buf = (UWORD8 *)ps_jobq->pv_buf_wr;
403 if((UWORD8 *)ps_jobq->pv_buf_end >= (pu1_buf + job_size))
404 {
405 memcpy(ps_jobq->pv_buf_wr, pv_job, job_size);
406 ps_jobq->pv_buf_wr = (UWORD8 *)ps_jobq->pv_buf_wr + job_size;
407 ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
408 }
409 else
410 {
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 ret = (IHEVCD_ERROR_T)IHEVCD_FAIL;
416 }
417
418 ps_jobq->i4_terminate = 0;
419
420 rettmp = ihevcd_jobq_unlock(ps_jobq);
421 RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
422
423 return ret;
424 }
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 */
ihevcd_jobq_dequeue(jobq_t * ps_jobq,void * pv_job,WORD32 job_size,WORD32 blocking)457 IHEVCD_ERROR_T ihevcd_jobq_dequeue(jobq_t *ps_jobq, void *pv_job, WORD32 job_size, WORD32 blocking)
458 {
459 IHEVCD_ERROR_T ret;
460 IHEVCD_ERROR_T rettmp;
461 volatile UWORD8 *pu1_buf;
462
463 rettmp = ihevcd_jobq_lock(ps_jobq);
464 RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
465 pu1_buf = (UWORD8 *)ps_jobq->pv_buf_rd;
466
467
468 if((UWORD8 *)ps_jobq->pv_buf_end >= (pu1_buf + job_size))
469 {
470 while(1)
471 {
472 pu1_buf = (UWORD8 *)ps_jobq->pv_buf_rd;
473 if((UWORD8 *)ps_jobq->pv_buf_wr >= (pu1_buf + job_size))
474 {
475 memcpy(pv_job, ps_jobq->pv_buf_rd, job_size);
476 ps_jobq->pv_buf_rd = (UWORD8 *)ps_jobq->pv_buf_rd + job_size;
477 ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
478 break;
479 }
480 else
481 {
482 /* If all the entries have been dequeued, then break and return */
483 if(1 == ps_jobq->i4_terminate)
484 {
485 ret = (IHEVCD_ERROR_T)IHEVCD_FAIL;
486 break;
487 }
488
489 if(1 == blocking)
490 {
491 ihevcd_jobq_yield(ps_jobq);
492
493 }
494 else
495 {
496 /* If there is no job available,
497 * and this is non blocking call then return fail */
498 ret = (IHEVCD_ERROR_T)IHEVCD_FAIL;
499 }
500 }
501 }
502 }
503 else
504 {
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 ret = (IHEVCD_ERROR_T)IHEVCD_FAIL;
510 }
511 rettmp = ihevcd_jobq_unlock(ps_jobq);
512 RETURN_IF((rettmp != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), rettmp);
513
514 return ret;
515 }
516