1 /*
2  * Copyright (C) 2019-2020 Alibaba Group Holding Limited
3  */
4 
5 #include <stdlib.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <aos/kernel.h>
10 #include <uservice/event.h>
11 #include <sys/select.h>
12 
13 #include "internal.h"
14 
15 #define FD_MASK (1UL << 31)
16 
17 typedef struct event {
18     uint32_t event_id;
19     slist_t  sub_list;
20 
21     slist_t next;
22 } event_t;
23 
24 typedef struct event_subscription {
25     event_callback_t ecb;
26     void *context;
27 
28     slist_t next;
29 } event_subscription_t;
30 
find_event(event_list_t * evlist,uint32_t event_id)31 static event_t *find_event(event_list_t *evlist, uint32_t event_id)
32 {
33     event_t *node;
34     slist_for_each_entry(&evlist->events, node, event_t, next) {
35         if (node->event_id == event_id) {
36             return node;
37         }
38     }
39 
40     return NULL;
41 }
42 
find_event_sub(event_t * ev,event_callback_t cb,void * context)43 static event_subscription_t *find_event_sub(event_t *ev, event_callback_t cb, void *context)
44 {
45     event_subscription_t *node;
46     slist_for_each_entry(&ev->sub_list, node, event_subscription_t, next) {
47         if (node->ecb == cb && node->context == context) {
48             return node;
49         }
50     }
51 
52     return NULL;
53 }
54 
eventlist_init(event_list_t * evlist)55 int eventlist_init(event_list_t *evlist)
56 {
57     aos_assert(evlist);
58 
59     memset(evlist, 0, sizeof(event_list_t));
60     slist_init(&evlist->events);
61 
62     if (aos_mutex_new(&evlist->mutex) != 0) {
63         return -1;
64     }
65 
66     return 0;
67 }
68 
eventlist_uninit(event_list_t * evlist)69 void eventlist_uninit(event_list_t *evlist)
70 {
71     aos_assert(evlist);
72     event_t *node;
73     slist_t *tmp_1;
74 
75     aos_mutex_lock(&evlist->mutex, AOS_WAIT_FOREVER);
76 
77     slist_for_each_entry_safe(&evlist->events, tmp_1, node, event_t, next) {
78         event_subscription_t *node_sub;
79         slist_t *tmp_2;
80         slist_for_each_entry_safe(&node->sub_list, tmp_2, node_sub, event_subscription_t, next) {
81             slist_del(&node_sub->next, &node->sub_list);
82             aos_free(node_sub);
83         }
84         slist_del(&node->next, &evlist->events);
85         aos_free(node);
86     }
87 
88     aos_mutex_unlock(&evlist->mutex);
89 
90     aos_mutex_free(&evlist->mutex);
91 }
92 
__yoc_event_subscribe(event_list_t * evlist,uint32_t event_id,event_callback_t cb,void * context)93 static int __yoc_event_subscribe(event_list_t *evlist, uint32_t event_id, event_callback_t cb, void *context)
94 {
95     int ret = -1;
96 
97     aos_mutex_lock(&evlist->mutex, AOS_WAIT_FOREVER);
98     event_t *ev = find_event(evlist, event_id);
99 
100     if (ev == NULL) {
101         ev = (event_t *)aos_zalloc(sizeof(event_t));
102 
103         if (ev != NULL) {
104             ev->event_id = event_id;
105             slist_init(&ev->sub_list);
106             slist_add(&ev->next, &evlist->events);
107         }
108     }
109 
110     if (ev != NULL) {
111         event_subscription_t *e_sub;
112         e_sub = find_event_sub(ev, cb, context);
113         if (e_sub == NULL) {
114             e_sub = (event_subscription_t *)aos_zalloc(sizeof(event_subscription_t));
115 
116             if (e_sub) {
117                 e_sub->ecb = cb;
118                 e_sub->context = context;
119                 slist_add(&e_sub->next, &ev->sub_list);
120 
121                 ret = 0;
122             }
123         }
124     }
125 
126     aos_mutex_unlock(&evlist->mutex);
127 
128     return ret;
129 }
130 
eventlist_subscribe_fd(event_list_t * evlist,uint32_t fd,event_callback_t cb,void * context)131 int eventlist_subscribe_fd(event_list_t *evlist, uint32_t fd, event_callback_t cb, void *context)
132 {
133     aos_assert(evlist && cb);
134     if (fd & FD_MASK) {
135         return -1;
136     }
137 
138     fd |= FD_MASK;
139 
140     return __yoc_event_subscribe(evlist, fd, cb, context);
141 }
142 
eventlist_subscribe(event_list_t * evlist,uint32_t event_id,event_callback_t cb,void * context)143 int eventlist_subscribe(event_list_t *evlist, uint32_t event_id, event_callback_t cb, void *context)
144 {
145     aos_assert(evlist && cb);
146     if (event_id & FD_MASK) {
147         return -1;
148     }
149 
150     return __yoc_event_subscribe(evlist, event_id, cb, context);
151 }
152 
__yoc_event_unsubscribe(event_list_t * evlist,uint32_t event_id,event_callback_t cb,void * context)153 static int __yoc_event_unsubscribe(event_list_t *evlist, uint32_t event_id, event_callback_t cb, void *context)
154 {
155     int ret = -1;
156 
157     aos_mutex_lock(&evlist->mutex, AOS_WAIT_FOREVER);
158 
159     event_t *ev = find_event(evlist, event_id);
160 
161     if (ev) {
162         event_subscription_t *e_sub = find_event_sub(ev, cb, context);
163 
164         if (e_sub) {
165             slist_del(&e_sub->next, &ev->sub_list);
166             aos_free(e_sub);
167 
168             if (slist_empty(&ev->sub_list)) {
169                 slist_del(&ev->next, &evlist->events);
170                 aos_free(ev);
171             }
172 
173             ret = 0;
174         }
175     }
176 
177     aos_mutex_unlock(&evlist->mutex);
178 
179     return ret;
180 }
181 
182 
__yoc_event_remove(event_list_t * evlist,uint32_t event_id)183 static int __yoc_event_remove(event_list_t *evlist, uint32_t event_id)
184 {
185     int ret = -1;
186 
187     aos_mutex_lock(&evlist->mutex, AOS_WAIT_FOREVER);
188 
189     event_t *ev = find_event(evlist, event_id);
190 
191     if (ev) {
192         event_subscription_t *node;
193         slist_t               *tmp;
194         slist_for_each_entry_safe(&ev->sub_list, tmp, node, event_subscription_t, next) {
195             slist_del(&ev->next, &evlist->events);
196             aos_free(ev);
197         }
198         slist_del(&ev->next, &evlist->events);
199         aos_free(ev);
200     }
201 
202     aos_mutex_unlock(&evlist->mutex);
203 
204     return ret;
205 }
206 
eventlist_unsubscribe_fd(event_list_t * evlist,uint32_t fd,event_callback_t cb,void * context)207 int eventlist_unsubscribe_fd(event_list_t *evlist, uint32_t fd, event_callback_t cb, void *context)
208 {
209     aos_assert(evlist && cb);
210     if (fd & FD_MASK) {
211         return -1;
212     }
213 
214     fd |= FD_MASK;
215 
216     return __yoc_event_unsubscribe(evlist, fd, cb, context);
217 }
218 
eventlist_unsubscribe(event_list_t * evlist,uint32_t event_id,event_callback_t cb,void * context)219 int eventlist_unsubscribe(event_list_t *evlist, uint32_t event_id, event_callback_t cb, void *context)
220 {
221     aos_assert(evlist && cb);
222     if (event_id & FD_MASK) {
223         return -1;
224     }
225 
226     return __yoc_event_unsubscribe(evlist, event_id, cb, context);
227 }
228 
__event_publish(event_list_t * evlist,uint32_t event_id,void * data)229 static void __event_publish(event_list_t *evlist, uint32_t event_id, void *data)
230 {
231     aos_mutex_lock(&evlist->mutex, AOS_WAIT_FOREVER);
232 
233     event_t *ev = find_event(evlist, event_id);
234 
235     if (ev) {
236         event_subscription_t *node;
237         slist_for_each_entry(&ev->sub_list, node, event_subscription_t, next) {
238             if (node->ecb) {
239                 node->ecb(ev->event_id, data, node->context);
240             }
241         }
242     }
243 
244     aos_mutex_unlock(&evlist->mutex);
245 }
246 
eventlist_publish(event_list_t * evlist,uint32_t event_id,void * data)247 int eventlist_publish(event_list_t *evlist, uint32_t event_id, void *data)
248 {
249     aos_assert(evlist);
250     if (event_id & FD_MASK) {
251         return -1;
252     }
253 
254     __event_publish(evlist, event_id, data);
255     return 0;
256 }
257 
eventlist_publish_fd(event_list_t * evlist,uint32_t fd,void * data)258 int eventlist_publish_fd(event_list_t *evlist, uint32_t fd, void *data)
259 {
260     aos_assert(evlist);
261     if (fd & FD_MASK) {
262         return -1;
263     }
264 
265     fd |= FD_MASK;
266     __event_publish(evlist, fd, data);
267 
268     return 0;
269 }
270 
eventlist_remove(event_list_t * evlist,uint32_t event_id)271 int eventlist_remove(event_list_t *evlist, uint32_t event_id)
272 {
273     aos_assert(evlist);
274     if (event_id & FD_MASK) {
275         return -1;
276     }
277     __yoc_event_remove(evlist, event_id);
278 
279     return 0;
280 }
281 
eventlist_remove_fd(event_list_t * evlist,uint32_t fd)282 int  eventlist_remove_fd(event_list_t *evlist, uint32_t fd)
283 {
284     aos_assert(evlist);
285     if (fd & FD_MASK) {
286         return -1;
287     }
288 
289     fd |= FD_MASK;
290     __yoc_event_remove(evlist, fd);
291 
292     return 0;
293 }
294 
eventlist_setfd(event_list_t * evlist,void * data)295 int eventlist_setfd(event_list_t *evlist, void *data)
296 {
297     aos_assert(evlist && data);
298     int max_fd = 0;
299 
300     fd_set *readfds = (fd_set *)data;
301 
302     FD_ZERO(readfds);
303 
304     aos_mutex_lock(&evlist->mutex, AOS_WAIT_FOREVER);
305     event_t *node;
306     slist_for_each_entry(&evlist->events, node, event_t, next) {
307         if (node->event_id > FD_MASK) {
308             uint32_t fd = node->event_id & (~FD_MASK);
309             FD_SET(fd, readfds);
310 
311             if (fd > max_fd) {
312                 max_fd = fd;
313             }
314         }
315     }
316     aos_mutex_unlock(&evlist->mutex);
317 
318     return max_fd;
319 }
320