xref: /rockchip-linux_mpp/test/mpp_event_trigger.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
1*437bfbebSnyanmisaka /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2*437bfbebSnyanmisaka /*
3*437bfbebSnyanmisaka  * Copyright (c) 2017 Rockchip Electronics Co., Ltd.
4*437bfbebSnyanmisaka  */
5*437bfbebSnyanmisaka 
6*437bfbebSnyanmisaka #include <assert.h>
7*437bfbebSnyanmisaka #include <errno.h>
8*437bfbebSnyanmisaka #include <malloc.h>
9*437bfbebSnyanmisaka #include <memory.h>
10*437bfbebSnyanmisaka #include <pthread.h>
11*437bfbebSnyanmisaka #include <stdio.h>
12*437bfbebSnyanmisaka #include <sys/time.h>
13*437bfbebSnyanmisaka #include <unistd.h>
14*437bfbebSnyanmisaka 
15*437bfbebSnyanmisaka #include "mpp_event_trigger.h"
16*437bfbebSnyanmisaka 
17*437bfbebSnyanmisaka #include "mpp_debug.h"
18*437bfbebSnyanmisaka 
19*437bfbebSnyanmisaka struct event_ctx_impl {
20*437bfbebSnyanmisaka     int (*notify)(void *param);
21*437bfbebSnyanmisaka 
22*437bfbebSnyanmisaka     event_trigger trigger;
23*437bfbebSnyanmisaka 
24*437bfbebSnyanmisaka     pthread_cond_t condition;
25*437bfbebSnyanmisaka     pthread_mutex_t mutex;
26*437bfbebSnyanmisaka     RK_U32 semval;
27*437bfbebSnyanmisaka 
28*437bfbebSnyanmisaka     pthread_t thr;
29*437bfbebSnyanmisaka     RK_S32 flag;
30*437bfbebSnyanmisaka 
31*437bfbebSnyanmisaka     struct event_packet *ea;
32*437bfbebSnyanmisaka     int event_idx;
33*437bfbebSnyanmisaka 
34*437bfbebSnyanmisaka     void *parent;
35*437bfbebSnyanmisaka };
36*437bfbebSnyanmisaka 
event_create(struct event_ctx_impl * ctx)37*437bfbebSnyanmisaka static int event_create(struct event_ctx_impl *ctx)
38*437bfbebSnyanmisaka {
39*437bfbebSnyanmisaka     int ret;
40*437bfbebSnyanmisaka 
41*437bfbebSnyanmisaka     ret = pthread_cond_init(&ctx->condition, NULL);
42*437bfbebSnyanmisaka     if (ret != 0)
43*437bfbebSnyanmisaka         return -1;
44*437bfbebSnyanmisaka 
45*437bfbebSnyanmisaka     ret = pthread_mutex_init(&ctx->mutex, NULL);
46*437bfbebSnyanmisaka     if (ret != 0)
47*437bfbebSnyanmisaka         return -1;
48*437bfbebSnyanmisaka 
49*437bfbebSnyanmisaka     ctx->semval = ctx->ea->e[0].idx;
50*437bfbebSnyanmisaka     mpp_log_f("with %u\n", ctx->semval);
51*437bfbebSnyanmisaka 
52*437bfbebSnyanmisaka     return 0;
53*437bfbebSnyanmisaka }
54*437bfbebSnyanmisaka 
event_destroy(struct event_ctx_impl * ctx)55*437bfbebSnyanmisaka static void event_destroy(struct event_ctx_impl *ctx)
56*437bfbebSnyanmisaka {
57*437bfbebSnyanmisaka     pthread_cond_destroy(&ctx->condition);
58*437bfbebSnyanmisaka     pthread_mutex_destroy(&ctx->mutex);
59*437bfbebSnyanmisaka }
60*437bfbebSnyanmisaka 
61*437bfbebSnyanmisaka /* initialize and schedule next event */
event_init(struct event_ctx_impl * ctx)62*437bfbebSnyanmisaka static void event_init(struct event_ctx_impl *ctx)
63*437bfbebSnyanmisaka {
64*437bfbebSnyanmisaka     struct ievent *e_curr;
65*437bfbebSnyanmisaka     struct ievent *e_next;
66*437bfbebSnyanmisaka 
67*437bfbebSnyanmisaka     pthread_mutex_lock(&ctx->mutex);
68*437bfbebSnyanmisaka     e_curr = &ctx->ea->e[ctx->event_idx % ctx->ea->cnt];
69*437bfbebSnyanmisaka     e_next = &ctx->ea->e[(++ctx->event_idx) % ctx->ea->cnt];
70*437bfbebSnyanmisaka 
71*437bfbebSnyanmisaka     mpp_log("curr %d, next %d\n",
72*437bfbebSnyanmisaka             e_curr->idx, e_next->idx);
73*437bfbebSnyanmisaka 
74*437bfbebSnyanmisaka     if (e_next->idx > e_curr->idx)
75*437bfbebSnyanmisaka         ctx->semval = e_next->idx - e_curr->idx;
76*437bfbebSnyanmisaka     else if (ctx->ea->loop > 0)
77*437bfbebSnyanmisaka         ctx->semval = e_next->idx + ctx->ea->loop - e_curr->idx;
78*437bfbebSnyanmisaka     else
79*437bfbebSnyanmisaka         ctx->flag = 0;
80*437bfbebSnyanmisaka 
81*437bfbebSnyanmisaka     mpp_log_f("semval %u\n", ctx->semval);
82*437bfbebSnyanmisaka     pthread_mutex_unlock(&ctx->mutex);
83*437bfbebSnyanmisaka }
84*437bfbebSnyanmisaka 
85*437bfbebSnyanmisaka /* wait the event trigger deadline */
86*437bfbebSnyanmisaka /*static void event_wait(struct event_ctx_impl *ctx)
87*437bfbebSnyanmisaka {
88*437bfbebSnyanmisaka     pthread_mutex_lock(&ctx->mutex);
89*437bfbebSnyanmisaka     while (ctx->semval > 0)
90*437bfbebSnyanmisaka         pthread_cond_wait(&ctx->condition, &ctx->mutex);
91*437bfbebSnyanmisaka 
92*437bfbebSnyanmisaka     ctx->semval--;
93*437bfbebSnyanmisaka     pthread_mutex_unlock(&ctx->mutex);
94*437bfbebSnyanmisaka }*/
95*437bfbebSnyanmisaka 
96*437bfbebSnyanmisaka /* wait the event trigger deadline with timeout, avoid dead lock */
event_timed_wait(struct event_ctx_impl * ctx,unsigned int milli_sec)97*437bfbebSnyanmisaka static int event_timed_wait(struct event_ctx_impl *ctx, unsigned int milli_sec)
98*437bfbebSnyanmisaka {
99*437bfbebSnyanmisaka     int err = 0;
100*437bfbebSnyanmisaka     struct timespec final_time;
101*437bfbebSnyanmisaka     struct timeval curr_time;
102*437bfbebSnyanmisaka     long int microdelay;
103*437bfbebSnyanmisaka 
104*437bfbebSnyanmisaka     gettimeofday(&curr_time, NULL);
105*437bfbebSnyanmisaka     /*
106*437bfbebSnyanmisaka      * convert timeval to timespec and add delay in milliseconds
107*437bfbebSnyanmisaka      * for the timeout
108*437bfbebSnyanmisaka      */
109*437bfbebSnyanmisaka     microdelay = ((milli_sec * 1000 + curr_time.tv_usec));
110*437bfbebSnyanmisaka     final_time.tv_sec = curr_time.tv_sec + (microdelay / 1000000);
111*437bfbebSnyanmisaka     final_time.tv_nsec = (microdelay % 1000000) * 1000;
112*437bfbebSnyanmisaka     pthread_mutex_lock(&ctx->mutex);
113*437bfbebSnyanmisaka     while (ctx->semval > 0) {
114*437bfbebSnyanmisaka         err = pthread_cond_timedwait(&ctx->condition, &ctx->mutex, &final_time);
115*437bfbebSnyanmisaka         if (err != 0)
116*437bfbebSnyanmisaka             ctx->semval--;
117*437bfbebSnyanmisaka     }
118*437bfbebSnyanmisaka     ctx->semval--;
119*437bfbebSnyanmisaka     pthread_mutex_unlock(&ctx->mutex);
120*437bfbebSnyanmisaka     return err;
121*437bfbebSnyanmisaka }
122*437bfbebSnyanmisaka 
123*437bfbebSnyanmisaka /* event heart beat */
event_down(struct event_ctx_impl * ctx)124*437bfbebSnyanmisaka static void event_down(struct event_ctx_impl *ctx)
125*437bfbebSnyanmisaka {
126*437bfbebSnyanmisaka     pthread_mutex_lock(&ctx->mutex);
127*437bfbebSnyanmisaka     ctx->semval--;
128*437bfbebSnyanmisaka     pthread_cond_signal(&ctx->condition);
129*437bfbebSnyanmisaka     pthread_mutex_unlock(&ctx->mutex);
130*437bfbebSnyanmisaka }
131*437bfbebSnyanmisaka 
132*437bfbebSnyanmisaka /* a callback to notify the event trigger that there is a event heart beat */
event_notify(void * param)133*437bfbebSnyanmisaka static int event_notify(void *param)
134*437bfbebSnyanmisaka {
135*437bfbebSnyanmisaka     struct event_ctx_impl *ctx = (struct event_ctx_impl *)param;
136*437bfbebSnyanmisaka 
137*437bfbebSnyanmisaka     if (ctx->flag)
138*437bfbebSnyanmisaka         event_down(ctx);
139*437bfbebSnyanmisaka 
140*437bfbebSnyanmisaka     return 0;
141*437bfbebSnyanmisaka }
142*437bfbebSnyanmisaka 
event_trigger_thread(void * param)143*437bfbebSnyanmisaka static void *event_trigger_thread(void *param)
144*437bfbebSnyanmisaka {
145*437bfbebSnyanmisaka     struct event_ctx_impl *ctx = (struct event_ctx_impl *)param;
146*437bfbebSnyanmisaka     struct timeval curr_time;
147*437bfbebSnyanmisaka     long start_time, curr;
148*437bfbebSnyanmisaka     RK_S32 ret;
149*437bfbebSnyanmisaka 
150*437bfbebSnyanmisaka     gettimeofday(&curr_time, NULL);
151*437bfbebSnyanmisaka 
152*437bfbebSnyanmisaka     start_time = curr_time.tv_sec * 1000 + curr_time.tv_usec / 1000;
153*437bfbebSnyanmisaka     event_create(ctx);
154*437bfbebSnyanmisaka 
155*437bfbebSnyanmisaka     while (1) {
156*437bfbebSnyanmisaka         ret = event_timed_wait(ctx, ctx->semval * 10000);
157*437bfbebSnyanmisaka         if (!ctx->flag)
158*437bfbebSnyanmisaka             break;
159*437bfbebSnyanmisaka 
160*437bfbebSnyanmisaka         if (ret == ETIMEDOUT) {
161*437bfbebSnyanmisaka             mpp_err("wait event timeout\n");
162*437bfbebSnyanmisaka             break;
163*437bfbebSnyanmisaka         }
164*437bfbebSnyanmisaka 
165*437bfbebSnyanmisaka         gettimeofday(&curr_time, NULL);
166*437bfbebSnyanmisaka 
167*437bfbebSnyanmisaka         curr = curr_time.tv_sec * 1000 + curr_time.tv_usec / 1000;
168*437bfbebSnyanmisaka         /* TODO, trigger event */
169*437bfbebSnyanmisaka         mpp_log("[%ld ms] event idx %d triggered\n",
170*437bfbebSnyanmisaka                 curr - start_time, ctx->event_idx);
171*437bfbebSnyanmisaka         mpp_log("cnt %d\n", ctx->ea->cnt);
172*437bfbebSnyanmisaka         ctx->trigger(ctx->parent, ctx->ea->e[ctx->event_idx % ctx->ea->cnt].event);
173*437bfbebSnyanmisaka 
174*437bfbebSnyanmisaka         /* schedule next event */
175*437bfbebSnyanmisaka         event_init(ctx);
176*437bfbebSnyanmisaka         if (!ctx->flag)
177*437bfbebSnyanmisaka             break;
178*437bfbebSnyanmisaka     }
179*437bfbebSnyanmisaka 
180*437bfbebSnyanmisaka     event_destroy(ctx);
181*437bfbebSnyanmisaka 
182*437bfbebSnyanmisaka     mpp_log_f("exit\n");
183*437bfbebSnyanmisaka 
184*437bfbebSnyanmisaka     return NULL;
185*437bfbebSnyanmisaka }
186*437bfbebSnyanmisaka 
event_ctx_create(struct event_packet * ea,event_trigger trigger,void * parent)187*437bfbebSnyanmisaka struct event_ctx* event_ctx_create(struct event_packet *ea,
188*437bfbebSnyanmisaka                                    event_trigger trigger, void *parent)
189*437bfbebSnyanmisaka {
190*437bfbebSnyanmisaka     struct event_ctx_impl *ctx = (struct event_ctx_impl *)malloc(sizeof(*ctx));
191*437bfbebSnyanmisaka 
192*437bfbebSnyanmisaka     if (ctx == NULL) {
193*437bfbebSnyanmisaka         mpp_err("allocate event ctx failed\n");
194*437bfbebSnyanmisaka         return NULL;
195*437bfbebSnyanmisaka     }
196*437bfbebSnyanmisaka 
197*437bfbebSnyanmisaka     assert(ea->cnt <= 128);
198*437bfbebSnyanmisaka 
199*437bfbebSnyanmisaka     ctx->event_idx = 0;
200*437bfbebSnyanmisaka     ctx->ea = ea;
201*437bfbebSnyanmisaka 
202*437bfbebSnyanmisaka     ctx->notify = event_notify;
203*437bfbebSnyanmisaka     ctx->trigger = trigger;
204*437bfbebSnyanmisaka     ctx->parent = parent;
205*437bfbebSnyanmisaka 
206*437bfbebSnyanmisaka     ctx->flag = 1;
207*437bfbebSnyanmisaka     pthread_create(&ctx->thr, NULL, event_trigger_thread, ctx);
208*437bfbebSnyanmisaka 
209*437bfbebSnyanmisaka     return (struct event_ctx *)ctx;
210*437bfbebSnyanmisaka }
211*437bfbebSnyanmisaka 
event_ctx_release(struct event_ctx * ctx)212*437bfbebSnyanmisaka void event_ctx_release(struct event_ctx *ctx)
213*437bfbebSnyanmisaka {
214*437bfbebSnyanmisaka     void *ret;
215*437bfbebSnyanmisaka     struct event_ctx_impl *ictx = (struct event_ctx_impl *)ctx;
216*437bfbebSnyanmisaka 
217*437bfbebSnyanmisaka     assert(ctx != NULL);
218*437bfbebSnyanmisaka 
219*437bfbebSnyanmisaka     if (ictx->flag) {
220*437bfbebSnyanmisaka         ictx->flag = 0;
221*437bfbebSnyanmisaka         ictx->semval = 0;
222*437bfbebSnyanmisaka         pthread_cond_signal(&ictx->condition);
223*437bfbebSnyanmisaka     }
224*437bfbebSnyanmisaka 
225*437bfbebSnyanmisaka     pthread_join(ictx->thr, &ret);
226*437bfbebSnyanmisaka 
227*437bfbebSnyanmisaka     free(ictx);
228*437bfbebSnyanmisaka }
229*437bfbebSnyanmisaka 
230*437bfbebSnyanmisaka #ifdef EVENT_TRIGGER_TEST
231*437bfbebSnyanmisaka /*
232*437bfbebSnyanmisaka  * the following codes is the sample to use the event trigger
233*437bfbebSnyanmisaka  */
234*437bfbebSnyanmisaka struct event_impl {
235*437bfbebSnyanmisaka     int cnt;
236*437bfbebSnyanmisaka     int loop;
237*437bfbebSnyanmisaka     int idx[128];
238*437bfbebSnyanmisaka     int event[128];
239*437bfbebSnyanmisaka };
240*437bfbebSnyanmisaka 
241*437bfbebSnyanmisaka /* a callback to notify test that a event occur */
event_occur(void * parent,void * event)242*437bfbebSnyanmisaka static void event_occur(void *parent, void *event)
243*437bfbebSnyanmisaka {
244*437bfbebSnyanmisaka     int *e = (int *)event;
245*437bfbebSnyanmisaka     mpp_log("event %d occur\n", *e);
246*437bfbebSnyanmisaka }
247*437bfbebSnyanmisaka 
main(int argc,char ** argv)248*437bfbebSnyanmisaka int main(int argc, char **argv)
249*437bfbebSnyanmisaka {
250*437bfbebSnyanmisaka     struct event_ctx *ctx;
251*437bfbebSnyanmisaka     int i = 0;
252*437bfbebSnyanmisaka     struct event_impl ie;
253*437bfbebSnyanmisaka     struct event_packet ea;
254*437bfbebSnyanmisaka 
255*437bfbebSnyanmisaka     ie.cnt = 4;
256*437bfbebSnyanmisaka     ie.loop = 25;
257*437bfbebSnyanmisaka     ie.event[0] = ie.idx[0] = 4;
258*437bfbebSnyanmisaka     ie.event[1] = ie.idx[1] = 8;
259*437bfbebSnyanmisaka     ie.event[2] = ie.idx[2] = 18;
260*437bfbebSnyanmisaka     ie.event[3] = ie.idx[3] = 20;
261*437bfbebSnyanmisaka 
262*437bfbebSnyanmisaka     ea.cnt = ie.cnt;
263*437bfbebSnyanmisaka     ea.loop = ie.loop;
264*437bfbebSnyanmisaka 
265*437bfbebSnyanmisaka     for (i = 0; i < ie.cnt; ++i) {
266*437bfbebSnyanmisaka         ea.e[i].idx = ie.idx[i];
267*437bfbebSnyanmisaka         ea.e[i].event = &ie.event[i];
268*437bfbebSnyanmisaka     }
269*437bfbebSnyanmisaka 
270*437bfbebSnyanmisaka     ctx = event_ctx_create(&ea, event_occur, NULL);
271*437bfbebSnyanmisaka 
272*437bfbebSnyanmisaka     while (i++ < 100) {
273*437bfbebSnyanmisaka         usleep(10 * 1000);
274*437bfbebSnyanmisaka         mpp_log("%03d:\n", i);
275*437bfbebSnyanmisaka         ctx->notify((void*)ctx);
276*437bfbebSnyanmisaka     }
277*437bfbebSnyanmisaka 
278*437bfbebSnyanmisaka     event_ctx_release(ctx);
279*437bfbebSnyanmisaka 
280*437bfbebSnyanmisaka     return 0;
281*437bfbebSnyanmisaka }
282*437bfbebSnyanmisaka #endif
283