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