libuv tidy up destroy and disable timer races during shutdown
[platform/upstream/libwebsockets.git] / lib / libuv.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  */
21
22 #include "private-libwebsockets.h"
23
24 void
25 lws_feature_status_libuv(struct lws_context_creation_info *info)
26 {
27         if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBUV))
28                 lwsl_notice("libuv support compiled in and enabled\n");
29         else
30                 lwsl_notice("libuv support compiled in but disabled\n");
31 }
32
33 static void
34 lws_uv_idle(uv_idle_t *handle
35 #if UV_VERSION_MAJOR == 0
36                 , int status
37 #endif
38 )
39 {
40         struct lws_context_per_thread *pt = lws_container_of(handle,
41                                         struct lws_context_per_thread, uv_idle);
42
43         lwsl_debug("%s\n", __func__);
44
45         /*
46          * is there anybody with pending stuff that needs service forcing?
47          */
48         if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) {
49                 /* -1 timeout means just do forced service */
50                 lws_plat_service_tsi(pt->context, -1, pt->tid);
51                 /* still somebody left who wants forced service? */
52                 if (!lws_service_adjust_timeout(pt->context, 1, pt->tid))
53                         /* yes... come back again later */
54                         lwsl_debug("%s: done again\n", __func__);
55                         return;
56         }
57
58         /* there is nobody who needs service forcing, shut down idle */
59         uv_idle_stop(handle);
60
61         lwsl_debug("%s: done stop\n", __func__);
62 }
63
64 static void
65 lws_io_cb(uv_poll_t *watcher, int status, int revents)
66 {
67         struct lws_io_watcher *lws_io = lws_container_of(watcher,
68                                         struct lws_io_watcher, uv_watcher);
69         struct lws *wsi = lws_container_of(lws_io, struct lws, w_read);
70         struct lws_context *context = lws_io->context;
71         struct lws_pollfd eventfd;
72
73 #if defined(WIN32) || defined(_WIN32)
74         eventfd.fd = watcher->socket;
75 #else
76         eventfd.fd = watcher->io_watcher.fd;
77 #endif
78         eventfd.events = 0;
79         eventfd.revents = 0;
80
81         if (status < 0) {
82                 /* at this point status will be an UV error, like UV_EBADF,
83                 we treat all errors as LWS_POLLHUP */
84
85                 /* you might want to return; instead of servicing the fd in some cases */
86                 if (status == UV_EAGAIN)
87                         return;
88
89                 eventfd.events |= LWS_POLLHUP;
90                 eventfd.revents |= LWS_POLLHUP;
91         } else {
92                 if (revents & UV_READABLE) {
93                         eventfd.events |= LWS_POLLIN;
94                         eventfd.revents |= LWS_POLLIN;
95                 }
96                 if (revents & UV_WRITABLE) {
97                         eventfd.events |= LWS_POLLOUT;
98                         eventfd.revents |= LWS_POLLOUT;
99                 }
100         }
101         lws_service_fd(context, &eventfd);
102
103         uv_idle_start(&context->pt[(int)wsi->tsi].uv_idle, lws_uv_idle);
104 }
105
106 LWS_VISIBLE void
107 lws_uv_sigint_cb(uv_signal_t *watcher, int signum)
108 {
109         lwsl_err("internal signal handler caught signal %d\n", signum);
110         lws_libuv_stop(watcher->data);
111 }
112
113 LWS_VISIBLE int
114 lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
115                   uv_signal_cb cb)
116 {
117         context->use_ev_sigint = use_uv_sigint;
118         if (cb)
119                 context->lws_uv_sigint_cb = cb;
120         else
121                 context->lws_uv_sigint_cb = &lws_uv_sigint_cb;
122
123         return 0;
124 }
125
126 static void
127 lws_uv_timeout_cb(uv_timer_t *timer
128 #if UV_VERSION_MAJOR == 0
129                 , int status
130 #endif
131 )
132 {
133         struct lws_context_per_thread *pt = lws_container_of(timer,
134                         struct lws_context_per_thread, uv_timeout_watcher);
135
136         if (pt->context->requested_kill)
137                 return;
138
139         lwsl_debug("%s\n", __func__);
140
141         lws_service_fd_tsi(pt->context, NULL, pt->tid);
142 }
143
144 static const int sigs[] = { SIGINT, SIGTERM, SIGSEGV, SIGFPE };
145
146 LWS_VISIBLE int
147 lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)
148 {
149         struct lws_context_per_thread *pt = &context->pt[tsi];
150         struct lws_vhost *vh = context->vhost_list;
151         int status = 0, n;
152
153         if (!loop) {
154                 loop = lws_malloc(sizeof(*loop));
155 #if UV_VERSION_MAJOR > 0
156                 uv_loop_init(loop);
157 #else
158                 lwsl_err("This libuv is too old to work...\n");
159                 return 1;
160 #endif
161                 pt->ev_loop_foreign = 0;
162         } else {
163                 lwsl_notice(" Using foreign event loop...\n");
164                 pt->ev_loop_foreign = 1;
165         }
166
167         pt->io_loop_uv = loop;
168         uv_idle_init(loop, &pt->uv_idle);
169
170         if (pt->context->use_ev_sigint) {
171                 assert(ARRAY_SIZE(sigs) <= ARRAY_SIZE(pt->signals));
172                 for (n = 0; n < ARRAY_SIZE(sigs); n++) {
173                         uv_signal_init(loop, &pt->signals[n]);
174                         pt->signals[n].data = pt->context;
175                         uv_signal_start(&pt->signals[n],
176                                         context->lws_uv_sigint_cb, sigs[n]);
177                 }
178         }
179
180         /*
181          * Initialize the accept wsi read watcher with all the listening sockets
182          * and register a callback for read operations
183          *
184          * We have to do it here because the uv loop(s) are not
185          * initialized until after context creation.
186          */
187         while (vh) {
188                 if (vh->lserv_wsi) {
189                         vh->lserv_wsi->w_read.context = context;
190                         n = uv_poll_init_socket(pt->io_loop_uv,
191                                                 &vh->lserv_wsi->w_read.uv_watcher,
192                                                 vh->lserv_wsi->sock);
193                         if (n) {
194                                 lwsl_err("uv_poll_init failed %d, sockfd=%p\n",
195                                         n, (void *)(long)vh->lserv_wsi->sock);
196
197                                 return -1;
198                         }
199                         lws_libuv_io(vh->lserv_wsi, LWS_EV_START | LWS_EV_READ);
200                 }
201                 vh = vh->vhost_next;
202         }
203
204         uv_timer_init(pt->io_loop_uv, &pt->uv_timeout_watcher);
205         uv_timer_start(&pt->uv_timeout_watcher, lws_uv_timeout_cb, 10, 1000);
206
207         return status;
208 }
209
210 static void lws_uv_close_cb(uv_handle_t *handle)
211 {
212         //lwsl_err("%s: handle %p\n", __func__, handle);
213 }
214
215 static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)
216 {
217         uv_close(handle, lws_uv_close_cb);
218 }
219
220 void
221 lws_libuv_destroyloop(struct lws_context *context, int tsi)
222 {
223         struct lws_context_per_thread *pt = &context->pt[tsi];
224         int m, budget = 100;
225
226         if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
227                 return;
228
229         if (!pt->io_loop_uv)
230                 return;
231
232         if (context->use_ev_sigint) {
233                 uv_signal_stop(&pt->w_sigint.uv_watcher);
234
235                 for (m = 0; m < ARRAY_SIZE(sigs); m++) {
236                         uv_signal_stop(&pt->signals[m]);
237                         uv_close((uv_handle_t *)&pt->signals[m], lws_uv_close_cb);
238                 }
239         }
240
241         uv_timer_stop(&pt->uv_timeout_watcher);
242         uv_close((uv_handle_t *)&pt->uv_timeout_watcher, lws_uv_close_cb);
243
244         uv_idle_stop(&pt->uv_idle);
245         uv_close((uv_handle_t *)&pt->uv_idle, lws_uv_close_cb);
246
247         while (budget-- && uv_run(pt->io_loop_uv, UV_RUN_NOWAIT))
248                 ;
249
250         if (pt->ev_loop_foreign)
251                 return;
252
253         uv_stop(pt->io_loop_uv);
254
255         uv_walk(pt->io_loop_uv, lws_uv_walk_cb, NULL);
256
257         while (uv_run(pt->io_loop_uv, UV_RUN_NOWAIT))
258                 ;
259 #if UV_VERSION_MAJOR > 0
260         m = uv_loop_close(pt->io_loop_uv);
261         if (m == UV_EBUSY)
262                 lwsl_err("%s: uv_loop_close: UV_EBUSY\n", __func__);
263 #endif
264         lws_free(pt->io_loop_uv);
265 }
266
267 void
268 lws_libuv_accept(struct lws *wsi, int accept_fd)
269 {
270         struct lws_context *context = lws_get_context(wsi);
271         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
272
273         if (!LWS_LIBUV_ENABLED(context))
274                 return;
275
276         lwsl_debug("%s: new wsi %p\n", __func__, wsi);
277
278         wsi->w_read.context = context;
279
280         uv_poll_init_socket(pt->io_loop_uv, &wsi->w_read.uv_watcher, accept_fd);
281 }
282
283 void
284 lws_libuv_io(struct lws *wsi, int flags)
285 {
286         struct lws_context *context = lws_get_context(wsi);
287         struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
288 #if defined(WIN32) || defined(_WIN32)
289         int current_events = wsi->w_read.uv_watcher.events &
290                              (UV_READABLE | UV_WRITABLE);
291 #else
292         int current_events = wsi->w_read.uv_watcher.io_watcher.pevents &
293                              (UV_READABLE | UV_WRITABLE);
294 #endif
295         struct lws_io_watcher *w = &wsi->w_read;
296
297         if (!LWS_LIBUV_ENABLED(context))
298                 return;
299
300         // lwsl_notice("%s: wsi: %p, flags:0x%x\n", __func__, wsi, flags);
301
302         if (!pt->io_loop_uv) {
303                 lwsl_info("%s: no io loop yet\n", __func__);
304                 return;
305         }
306
307         assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
308                (flags & (LWS_EV_READ | LWS_EV_WRITE)));
309
310         if (flags & LWS_EV_START) {
311                 if (flags & LWS_EV_WRITE)
312                         current_events |= UV_WRITABLE;
313
314                 if (flags & LWS_EV_READ)
315                         current_events |= UV_READABLE;
316
317                 uv_poll_start(&w->uv_watcher, current_events, lws_io_cb);
318         } else {
319                 if (flags & LWS_EV_WRITE)
320                         current_events &= ~UV_WRITABLE;
321
322                 if (flags & LWS_EV_READ)
323                         current_events &= ~UV_READABLE;
324
325                 if (!(current_events & (UV_READABLE | UV_WRITABLE)))
326                         uv_poll_stop(&w->uv_watcher);
327                 else
328                         uv_poll_start(&w->uv_watcher, current_events,
329                                       lws_io_cb);
330         }
331 }
332
333 int
334 lws_libuv_init_fd_table(struct lws_context *context)
335 {
336         int n;
337
338         if (!LWS_LIBUV_ENABLED(context))
339                 return 0;
340
341         for (n = 0; n < context->count_threads; n++)
342                 context->pt[n].w_sigint.context = context;
343
344         return 1;
345 }
346
347 LWS_VISIBLE void
348 lws_libuv_run(const struct lws_context *context, int tsi)
349 {
350         if (context->pt[tsi].io_loop_uv && LWS_LIBUV_ENABLED(context))
351                 uv_run(context->pt[tsi].io_loop_uv, 0);
352 }
353
354 static void
355 lws_libuv_kill(const struct lws_context *context)
356 {
357         int n;
358
359         for (n = 0; n < context->count_threads; n++)
360                 if (context->pt[n].io_loop_uv &&
361                     LWS_LIBUV_ENABLED(context) &&
362                     !context->pt[n].ev_loop_foreign)
363                         uv_stop(context->pt[n].io_loop_uv);
364 }
365
366 /*
367  * This does not actually stop the event loop.  The reason is we have to pass
368  * libuv handle closures through its event loop.  So this tries to close all
369  * wsi, and set a flag; when all the wsi closures are finalized then we
370  * actually stop the libuv event loops.
371  */
372
373 LWS_VISIBLE void
374 lws_libuv_stop(struct lws_context *context)
375 {
376         struct lws_context_per_thread *pt;
377         int n, m;
378
379         if (context->requested_kill)
380                 return;
381
382         context->requested_kill = 1;
383
384         m = context->count_threads;
385         context->being_destroyed = 1;
386
387         while (m--) {
388                 pt = &context->pt[m];
389
390                 for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
391                         struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
392
393                         if (!wsi)
394                                 continue;
395                         lws_close_free_wsi(wsi,
396                                 LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
397                                 /* no protocol close */);
398                         n--;
399                 }
400         }
401
402         lwsl_info("%s: feels everything closed\n", __func__);
403         if (context->count_wsi_allocated == 0)
404                 lws_libuv_kill(context);
405 }
406
407 LWS_VISIBLE uv_loop_t *
408 lws_uv_getloop(struct lws_context *context, int tsi)
409 {
410         if (context->pt[tsi].io_loop_uv && LWS_LIBUV_ENABLED(context))
411                 return context->pt[tsi].io_loop_uv;
412
413         return NULL;
414 }
415
416 static void
417 lws_libuv_closewsi(uv_handle_t* handle)
418 {
419         struct lws *n = NULL, *wsi = (struct lws *)(((char *)handle) -
420                           (char *)(&n->w_read.uv_watcher));
421         struct lws_context *context = lws_get_context(wsi);
422
423         lws_close_free_wsi_final(wsi);
424
425         if (context->requested_kill && context->count_wsi_allocated == 0)
426                 lws_libuv_kill(context);
427 }
428
429 void
430 lws_libuv_closehandle(struct lws *wsi)
431 {
432         struct lws_context *context = lws_get_context(wsi);
433
434         /* required to defer actual deletion until libuv has processed it */
435
436         uv_close((uv_handle_t*)&wsi->w_read.uv_watcher, lws_libuv_closewsi);
437
438         if (context->requested_kill && context->count_wsi_allocated == 0)
439                 lws_libuv_kill(context);
440 }
441
442 #if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
443
444 LWS_VISIBLE int
445 lws_plat_plugins_init(struct lws_context * context, const char * const *d)
446 {
447         struct lws_plugin_capability lcaps;
448         struct lws_plugin *plugin;
449         lws_plugin_init_func initfunc;
450         int m, ret = 0;
451         void *v;
452         uv_dirent_t dent;
453         uv_fs_t req;
454         char path[256];
455         uv_loop_t loop;
456         uv_lib_t lib;
457
458         lib.errmsg = NULL;
459         lib.handle = NULL;
460
461         uv_loop_init(&loop);
462
463         lwsl_notice("  Plugins:\n");
464
465         while (d && *d) {
466
467                 lwsl_notice("  Scanning %s\n", *d);
468                 m =uv_fs_scandir(&loop, &req, *d, 0, NULL);
469                 if (m < 1) {
470                         lwsl_err("Scandir on %s failed\n", *d);
471                         return 1;
472                 }
473
474                 while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
475                         if (strlen(dent.name) < 7)
476                                 continue;
477
478                         lwsl_notice("   %s\n", dent.name);
479
480                         snprintf(path, sizeof(path) - 1, "%s/%s", *d, dent.name);
481                         if (uv_dlopen(path, &lib)) {
482                                 uv_dlerror(&lib);
483                                 lwsl_err("Error loading DSO: %s\n", lib.errmsg);
484                                 goto bail;
485                         }
486                         /* we could open it, can we get his init function? */
487                         m = snprintf(path, sizeof(path) - 1, "init_%s",
488                                      dent.name + 3 /* snip lib... */);
489                         path[m - 3] = '\0'; /* snip the .so */
490                         if (uv_dlsym(&lib, path, &v)) {
491                                 uv_dlerror(&lib);
492                                 lwsl_err("Failed to get init on %s: %s",
493                                                 dent.name, lib.errmsg);
494                                 goto bail;
495                         }
496                         initfunc = (lws_plugin_init_func)v;
497                         lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
498                         m = initfunc(context, &lcaps);
499                         if (m) {
500                                 lwsl_err("Initializing %s failed %d\n", dent.name, m);
501                                 goto skip;
502                         }
503
504                         plugin = lws_malloc(sizeof(*plugin));
505                         if (!plugin) {
506                                 lwsl_err("OOM\n");
507                                 goto bail;
508                         }
509                         plugin->list = context->plugin_list;
510                         context->plugin_list = plugin;
511                         strncpy(plugin->name, dent.name, sizeof(plugin->name) - 1);
512                         plugin->name[sizeof(plugin->name) - 1] = '\0';
513                         plugin->lib = lib;
514                         plugin->caps = lcaps;
515                         context->plugin_protocol_count += lcaps.count_protocols;
516                         context->plugin_extension_count += lcaps.count_extensions;
517
518                         continue;
519
520 skip:
521                         uv_dlclose(&lib);
522                 }
523 bail:
524                 uv_fs_req_cleanup(&req);
525                 d++;
526         }
527
528         uv_loop_close(&loop);
529
530         return ret;
531
532 }
533
534 LWS_VISIBLE int
535 lws_plat_plugins_destroy(struct lws_context * context)
536 {
537         struct lws_plugin *plugin = context->plugin_list, *p;
538         lws_plugin_destroy_func func;
539         char path[256];
540         void *v;
541         int m;
542
543         if (!plugin)
544                 return 0;
545
546         // lwsl_notice("%s\n", __func__);
547
548         while (plugin) {
549                 p = plugin;
550                 m = snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + 3);
551                 path[m - 3] = '\0';
552
553                 if (uv_dlsym(&plugin->lib, path, &v)) {
554                         uv_dlerror(&plugin->lib);
555                         lwsl_err("Failed to get init on %s: %s",
556                                         plugin->name, plugin->lib.errmsg);
557                 } else {
558                         func = (lws_plugin_destroy_func)v;
559                         m = func(context);
560                         if (m)
561                                 lwsl_err("Destroying %s failed %d\n",
562                                                 plugin->name, m);
563                 }
564
565                 uv_dlclose(&p->lib);
566                 plugin = p->list;
567                 p->list = NULL;
568                 free(p);
569         }
570
571         context->plugin_list = NULL;
572
573         return 0;
574 }
575
576 #endif
577