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