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