1 /*
2  * Authored by Alex Hultman, 2018-2021.
3  * Intellectual property of third-party.
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 #include "libusockets.h"
19 #include "internal/internal.h"
20 #include <stdlib.h>
21 
22 #ifdef LIBUS_USE_LIBUV
23 
24 /* uv_poll_t->data always (except for most times after calling us_poll_stop) points to the us_poll_t */
poll_cb(uv_poll_t * p,int status,int events)25 static void poll_cb(uv_poll_t *p, int status, int events) {
26     us_internal_dispatch_ready_poll((struct us_poll_t *) p->data, status < 0, events);
27 }
28 
prepare_cb(uv_prepare_t * p)29 static void prepare_cb(uv_prepare_t *p) {
30     struct us_loop_t *loop = p->data;
31     us_internal_loop_pre(loop);
32 }
33 
34 /* Note: libuv timers execute AFTER the post callback */
check_cb(uv_check_t * p)35 static void check_cb(uv_check_t *p) {
36     struct us_loop_t *loop = p->data;
37     us_internal_loop_post(loop);
38 }
39 
40 /* Not used for polls, since polls need two frees */
close_cb_free(uv_handle_t * h)41 static void close_cb_free(uv_handle_t *h) {
42     free(h->data);
43 }
44 
45 /* This one is different for polls, since we need two frees here */
close_cb_free_poll(uv_handle_t * h)46 static void close_cb_free_poll(uv_handle_t *h) {
47     /* It is only in case we called us_poll_stop then quickly us_poll_free that we enter this.
48      * Most of the time, actual freeing is done by us_poll_free. */
49     if (h->data) {
50         free(h->data);
51         free(h);
52     }
53 }
54 
timer_cb(uv_timer_t * t)55 static void timer_cb(uv_timer_t *t) {
56     struct us_internal_callback_t *cb = t->data;
57     cb->cb(cb);
58 }
59 
async_cb(uv_async_t * a)60 static void async_cb(uv_async_t *a) {
61     struct us_internal_callback_t *cb = a->data;
62     // internal asyncs give their loop, not themselves
63     cb->cb((struct us_internal_callback_t *) cb->loop);
64 }
65 
66 // poll
us_poll_init(struct us_poll_t * p,LIBUS_SOCKET_DESCRIPTOR fd,int poll_type)67 void us_poll_init(struct us_poll_t *p, LIBUS_SOCKET_DESCRIPTOR fd, int poll_type) {
68     p->poll_type = poll_type;
69     p->fd = fd;
70 }
71 
us_poll_free(struct us_poll_t * p,struct us_loop_t * loop)72 void us_poll_free(struct us_poll_t *p, struct us_loop_t *loop) {
73     /* The idea here is like so; in us_poll_stop we call uv_close after setting data of uv-poll to 0.
74      * This means that in close_cb_free we call free on 0 with does nothing, since us_poll_stop should
75      * not really free the poll. HOWEVER, if we then call us_poll_free while still closing the uv-poll,
76      * we simply change back the data to point to our structure so that we actually do free it like we should. */
77     if (uv_is_closing((uv_handle_t *) p->uv_p)) {
78         p->uv_p->data = p;
79     } else {
80         free(p->uv_p);
81         free(p);
82     }
83 }
84 
us_poll_start(struct us_poll_t * p,struct us_loop_t * loop,int events)85 void us_poll_start(struct us_poll_t *p, struct us_loop_t *loop, int events) {
86     p->poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0) | ((events & LIBUS_SOCKET_WRITABLE) ? POLL_TYPE_POLLING_OUT : 0);
87 
88     uv_poll_init_socket(loop->uv_loop, p->uv_p, p->fd);
89     uv_poll_start(p->uv_p, events, poll_cb);
90 }
91 
us_poll_change(struct us_poll_t * p,struct us_loop_t * loop,int events)92 void us_poll_change(struct us_poll_t *p, struct us_loop_t *loop, int events) {
93     if (us_poll_events(p) != events) {
94         p->poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0) | ((events & LIBUS_SOCKET_WRITABLE) ? POLL_TYPE_POLLING_OUT : 0);
95 
96         uv_poll_start(p->uv_p, events, poll_cb);
97     }
98 }
99 
us_poll_stop(struct us_poll_t * p,struct us_loop_t * loop)100 void us_poll_stop(struct us_poll_t *p, struct us_loop_t *loop) {
101     uv_poll_stop(p->uv_p);
102 
103     /* We normally only want to close the poll here, not free it. But if we stop it, then quickly "free" it with
104      * us_poll_free, we postpone the actual freeing to close_cb_free_poll whenever it triggers.
105      * That's why we set data to null here, so that us_poll_free can reset it if needed */
106     p->uv_p->data = 0;
107     uv_close((uv_handle_t *) p->uv_p, close_cb_free_poll);
108 }
109 
us_poll_events(struct us_poll_t * p)110 int us_poll_events(struct us_poll_t *p) {
111     return ((p->poll_type & POLL_TYPE_POLLING_IN) ? LIBUS_SOCKET_READABLE : 0) | ((p->poll_type & POLL_TYPE_POLLING_OUT) ? LIBUS_SOCKET_WRITABLE : 0);
112 }
113 
us_internal_accept_poll_event(struct us_poll_t * p)114 unsigned int us_internal_accept_poll_event(struct us_poll_t *p) {
115     return 0;
116 }
117 
us_internal_poll_type(struct us_poll_t * p)118 int us_internal_poll_type(struct us_poll_t *p) {
119     return p->poll_type & 3;
120 }
121 
us_internal_poll_set_type(struct us_poll_t * p,int poll_type)122 void us_internal_poll_set_type(struct us_poll_t *p, int poll_type) {
123     p->poll_type = poll_type | (p->poll_type & 12);
124 }
125 
us_poll_fd(struct us_poll_t * p)126 LIBUS_SOCKET_DESCRIPTOR us_poll_fd(struct us_poll_t *p) {
127     return p->fd;
128 }
129 
us_create_loop(void * hint,void (* wakeup_cb)(struct us_loop_t * loop),void (* pre_cb)(struct us_loop_t * loop),void (* post_cb)(struct us_loop_t * loop),unsigned int ext_size)130 struct us_loop_t *us_create_loop(void *hint, void (*wakeup_cb)(struct us_loop_t *loop), void (*pre_cb)(struct us_loop_t *loop), void (*post_cb)(struct us_loop_t *loop), unsigned int ext_size) {
131     struct us_loop_t *loop = (struct us_loop_t *) malloc(sizeof(struct us_loop_t) + ext_size);
132 
133     loop->uv_loop = hint ? hint : uv_loop_new();
134     loop->is_default = hint != 0;
135 
136     loop->uv_pre = malloc(sizeof(uv_prepare_t));
137     uv_prepare_init(loop->uv_loop, loop->uv_pre);
138     uv_prepare_start(loop->uv_pre, prepare_cb);
139     uv_unref((uv_handle_t *) loop->uv_pre);
140     loop->uv_pre->data = loop;
141 
142     loop->uv_check = malloc(sizeof(uv_check_t));
143     uv_check_init(loop->uv_loop, loop->uv_check);
144     uv_unref((uv_handle_t *) loop->uv_check);
145     uv_check_start(loop->uv_check, check_cb);
146     loop->uv_check->data = loop;
147 
148     // here we create two unreffed handles - timer and async
149     us_internal_loop_data_init(loop, wakeup_cb, pre_cb, post_cb);
150 
151     // if we do not own this loop, we need to integrate and set up timer
152     if (hint) {
153         us_loop_integrate(loop);
154     }
155 
156     return loop;
157 }
158 
159 // based on if this was default loop or not
us_loop_free(struct us_loop_t * loop)160 void us_loop_free(struct us_loop_t *loop) {
161     // ref and close down prepare and check
162     uv_ref((uv_handle_t *) loop->uv_pre);
163     uv_prepare_stop(loop->uv_pre);
164     loop->uv_pre->data = loop->uv_pre;
165     uv_close((uv_handle_t *) loop->uv_pre, close_cb_free);
166 
167     uv_ref((uv_handle_t *) loop->uv_check);
168     uv_check_stop(loop->uv_check);
169     loop->uv_check->data = loop->uv_check;
170     uv_close((uv_handle_t *) loop->uv_check, close_cb_free);
171 
172     us_internal_loop_data_free(loop);
173 
174     // we need to run the loop one last round to call all close callbacks
175     // we cannot do this if we do not own the loop, default
176     if (!loop->is_default) {
177         uv_run(loop->uv_loop, UV_RUN_NOWAIT);
178         uv_loop_delete(loop->uv_loop);
179     }
180 
181     // now we can free our part
182     free(loop);
183 }
184 
us_loop_run(struct us_loop_t * loop)185 void us_loop_run(struct us_loop_t *loop) {
186     us_loop_integrate(loop);
187 
188     uv_run(loop->uv_loop, UV_RUN_DEFAULT);
189 }
190 
us_create_poll(struct us_loop_t * loop,int fallthrough,unsigned int ext_size)191 struct us_poll_t *us_create_poll(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) {
192     struct us_poll_t *p = (struct us_poll_t *) malloc(sizeof(struct us_poll_t) + ext_size);
193     p->uv_p = malloc(sizeof(uv_poll_t));
194     p->uv_p->data = p;
195     return p;
196 }
197 
198 /* If we update our block position we have to updarte the uv_poll data to point to us */
us_poll_resize(struct us_poll_t * p,struct us_loop_t * loop,unsigned int ext_size)199 struct us_poll_t *us_poll_resize(struct us_poll_t *p, struct us_loop_t *loop, unsigned int ext_size) {
200 
201     struct us_poll_t *new_p = realloc(p, sizeof(struct us_poll_t) + ext_size);
202     new_p->uv_p->data = new_p;
203 
204     return new_p;
205 }
206 
207 // timer
us_create_timer(struct us_loop_t * loop,int fallthrough,unsigned int ext_size)208 struct us_timer_t *us_create_timer(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) {
209     struct us_internal_callback_t *cb = malloc(sizeof(struct us_internal_callback_t) + sizeof(uv_timer_t) + ext_size);
210 
211     cb->loop = loop;
212     cb->cb_expects_the_loop = 0;
213 
214     uv_timer_t *uv_timer = (uv_timer_t *) (cb + 1);
215     uv_timer_init(loop->uv_loop, uv_timer);
216     uv_timer->data = cb;
217 
218     if (fallthrough) {
219         uv_unref((uv_handle_t *) uv_timer);
220     }
221 
222     return (struct us_timer_t *) cb;
223 }
224 
us_timer_ext(struct us_timer_t * timer)225 void *us_timer_ext(struct us_timer_t *timer) {
226     return ((char *) timer) + sizeof(struct us_internal_callback_t) + sizeof(uv_timer_t);
227 }
228 
us_timer_close(struct us_timer_t * t)229 void us_timer_close(struct us_timer_t *t) {
230     struct us_internal_callback_t *cb = (struct us_internal_callback_t *) t;
231 
232     uv_timer_t *uv_timer = (uv_timer_t *) (cb + 1);
233 
234     // always ref the timer before closing it
235     uv_ref((uv_handle_t *) uv_timer);
236 
237     uv_timer_stop(uv_timer);
238 
239     uv_timer->data = cb;
240     uv_close((uv_handle_t *) uv_timer, close_cb_free);
241 }
242 
us_timer_set(struct us_timer_t * t,void (* cb)(struct us_timer_t * t),int ms,int repeat_ms)243 void us_timer_set(struct us_timer_t *t, void (*cb)(struct us_timer_t *t), int ms, int repeat_ms) {
244     struct us_internal_callback_t *internal_cb = (struct us_internal_callback_t *) t;
245 
246     internal_cb->cb = (void(*)(struct us_internal_callback_t *)) cb;
247 
248     uv_timer_t *uv_timer = (uv_timer_t *) (internal_cb + 1);
249     if (!ms) {
250         uv_timer_stop(uv_timer);
251     } else {
252         uv_timer_start(uv_timer, timer_cb, ms, repeat_ms);
253     }
254 }
255 
us_timer_loop(struct us_timer_t * t)256 struct us_loop_t *us_timer_loop(struct us_timer_t *t) {
257     struct us_internal_callback_t *internal_cb = (struct us_internal_callback_t *) t;
258 
259     return internal_cb->loop;
260 }
261 
262 // async (internal only)
us_internal_create_async(struct us_loop_t * loop,int fallthrough,unsigned int ext_size)263 struct us_internal_async *us_internal_create_async(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) {
264     struct us_internal_callback_t *cb = malloc(sizeof(struct us_internal_callback_t) + sizeof(uv_async_t) + ext_size);
265 
266     cb->loop = loop;
267     return (struct us_internal_async *) cb;
268 }
269 
us_internal_async_close(struct us_internal_async * a)270 void us_internal_async_close(struct us_internal_async *a) {
271     struct us_internal_callback_t *cb = (struct us_internal_callback_t *) a;
272 
273     uv_async_t *uv_async = (uv_async_t *) (cb + 1);
274 
275     // always ref the async before closing it
276     uv_ref((uv_handle_t *) uv_async);
277 
278     uv_async->data = cb;
279     uv_close((uv_handle_t *) uv_async, close_cb_free);
280 }
281 
us_internal_async_set(struct us_internal_async * a,void (* cb)(struct us_internal_async *))282 void us_internal_async_set(struct us_internal_async *a, void (*cb)(struct us_internal_async *)) {
283     struct us_internal_callback_t *internal_cb = (struct us_internal_callback_t *) a;
284 
285     internal_cb->cb = (void (*)(struct us_internal_callback_t *)) cb;
286 
287     uv_async_t *uv_async = (uv_async_t *) (internal_cb + 1);
288     uv_async_init(internal_cb->loop->uv_loop, uv_async, async_cb);
289     uv_unref((uv_handle_t *) uv_async);
290     uv_async->data = internal_cb;
291 }
292 
us_internal_async_wakeup(struct us_internal_async * a)293 void us_internal_async_wakeup(struct us_internal_async *a) {
294     struct us_internal_callback_t *internal_cb = (struct us_internal_callback_t *) a;
295 
296     uv_async_t *uv_async = (uv_async_t *) (internal_cb + 1);
297     uv_async_send(uv_async);
298 }
299 
300 #endif
301