| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- /*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2020 Andy Green <[email protected]>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #include "private-lib-core.h"
- #include "private-lib-event-libs-libev.h"
- #define pt_to_priv_ev(_pt) ((struct lws_pt_eventlibs_libev *)(_pt)->evlib_pt)
- #define vh_to_priv_ev(_vh) ((struct lws_vh_eventlibs_libev *)(_vh)->evlib_vh)
- #define wsi_to_priv_ev(_w) ((struct lws_wsi_eventlibs_libev *)(_w)->evlib_wsi)
- static void
- lws_ev_hrtimer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents)
- {
- struct lws_pt_eventlibs_libev *ptpr = lws_container_of(watcher,
- struct lws_pt_eventlibs_libev, hrtimer);
- struct lws_context_per_thread *pt = ptpr->pt;
- lws_usec_t us;
- lws_pt_lock(pt, __func__);
- us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
- lws_now_usecs());
- if (us) {
- ev_timer_set(&ptpr->hrtimer, ((float)us) / 1000000.0, 0);
- ev_timer_start(ptpr->io_loop, &ptpr->hrtimer);
- }
- lws_pt_unlock(pt);
- }
- static void
- lws_ev_idle_cb(struct ev_loop *loop, struct ev_idle *handle, int revents)
- {
- struct lws_pt_eventlibs_libev *ptpr = lws_container_of(handle,
- struct lws_pt_eventlibs_libev, idle);
- struct lws_context_per_thread *pt = ptpr->pt;
- int reschedule = 0;
- lws_usec_t us;
- lws_service_do_ripe_rxflow(pt);
- /*
- * is there anybody with pending stuff that needs service forcing?
- */
- if (!lws_service_adjust_timeout(pt->context, 1, pt->tid))
- /* -1 timeout means just do forced service */
- reschedule = _lws_plat_service_forced_tsi(pt->context, pt->tid);
- /* account for hrtimer */
- lws_pt_lock(pt, __func__);
- us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
- lws_now_usecs());
- if (us) {
- ev_timer_set(&ptpr->hrtimer, ((float)us) / 1000000.0, 0);
- ev_timer_start(ptpr->io_loop, &ptpr->hrtimer);
- }
- lws_pt_unlock(pt);
- /* there is nobody who needs service forcing, shut down idle */
- if (!reschedule)
- ev_idle_stop(loop, handle);
- if (pt->destroy_self)
- lws_context_destroy(pt->context);
- }
- static void
- lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
- {
- struct lws_io_watcher_libev *lws_io = lws_container_of(watcher,
- struct lws_io_watcher_libev, watcher);
- struct lws_context *context = lws_io->context;
- struct lws_pt_eventlibs_libev *ptpr;
- struct lws_context_per_thread *pt;
- struct lws_pollfd eventfd;
- struct lws *wsi;
- if (revents & EV_ERROR)
- return;
- eventfd.fd = watcher->fd;
- eventfd.events = 0;
- eventfd.revents = EV_NONE;
- if (revents & EV_READ) {
- eventfd.events |= LWS_POLLIN;
- eventfd.revents |= LWS_POLLIN;
- }
- if (revents & EV_WRITE) {
- eventfd.events |= LWS_POLLOUT;
- eventfd.revents |= LWS_POLLOUT;
- }
- wsi = wsi_from_fd(context, watcher->fd);
- pt = &context->pt[(int)wsi->tsi];
- ptpr = pt_to_priv_ev(pt);
- lws_service_fd_tsi(context, &eventfd, (int)wsi->tsi);
- ev_idle_start(ptpr->io_loop, &ptpr->idle);
- }
- void
- lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents)
- {
- struct lws_context *context = watcher->data;
- if (context->eventlib_signal_cb) {
- context->eventlib_signal_cb((void *)watcher, watcher->signum);
- return;
- }
- ev_break(loop, EVBREAK_ALL);
- }
- static int
- elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi)
- {
- struct lws_context_per_thread *pt = &context->pt[tsi];
- struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
- struct ev_signal *w_sigint = &ptpr->w_sigint.watcher;
- struct ev_loop *loop = (struct ev_loop *)_loop;
- struct lws_vhost *vh = context->vhost_list;
- const char *backend_name;
- int status = 0;
- int backend;
- lwsl_info("%s: loop %p\n", __func__, _loop);
- ptpr->pt = pt;
- if (!loop)
- loop = ev_loop_new(0);
- else
- context->pt[tsi].event_loop_foreign = 1;
- if (!loop) {
- lwsl_err("%s: creating event base failed\n", __func__);
- return -1;
- }
- ptpr->io_loop = loop;
- /*
- * Initialize the accept w_accept with all the listening sockets
- * and register a callback for read operations
- */
- while (vh) {
- if (vh->lserv_wsi) {
- struct lws_wsi_eventlibs_libev *w =
- wsi_to_priv_ev(vh->lserv_wsi);
- w->w_read.context = context;
- w->w_write.context = context;
- vh_to_priv_ev(vh)->w_accept.context = context;
- ev_io_init(&vh_to_priv_ev(vh)->w_accept.watcher,
- lws_accept_cb,
- vh->lserv_wsi->desc.sockfd, EV_READ);
- ev_io_start(loop, &vh_to_priv_ev(vh)->w_accept.watcher);
- }
- vh = vh->vhost_next;
- }
- /* Register the signal watcher unless it's a foreign loop */
- if (!context->pt[tsi].event_loop_foreign) {
- ev_signal_init(w_sigint, lws_ev_sigint_cb, SIGINT);
- w_sigint->data = context;
- ev_signal_start(loop, w_sigint);
- }
- backend = ev_backend(loop);
- switch (backend) {
- case EVBACKEND_SELECT:
- backend_name = "select";
- break;
- case EVBACKEND_POLL:
- backend_name = "poll";
- break;
- case EVBACKEND_EPOLL:
- backend_name = "epoll";
- break;
- #if defined(LWS_HAVE_EVBACKEND_LINUXAIO)
- case EVBACKEND_LINUXAIO:
- backend_name = "Linux AIO";
- break;
- #endif
- #if defined(LWS_HAVE_EVBACKEND_IOURING)
- case EVBACKEND_IOURING:
- backend_name = "Linux io_uring";
- break;
- #endif
- case EVBACKEND_KQUEUE:
- backend_name = "kqueue";
- break;
- case EVBACKEND_DEVPOLL:
- backend_name = "/dev/poll";
- break;
- case EVBACKEND_PORT:
- backend_name = "Solaris 10 \"port\"";
- break;
- default:
- backend_name = "Unknown libev backend";
- break;
- }
- lwsl_info(" libev backend: %s\n", backend_name);
- (void)backend_name;
- ev_timer_init(&ptpr->hrtimer, lws_ev_hrtimer_cb, 0, 0);
- ptpr->hrtimer.data = pt;
- ev_idle_init(&ptpr->idle, lws_ev_idle_cb);
- return status;
- }
- static void
- elops_destroy_pt_ev(struct lws_context *context, int tsi)
- {
- struct lws_context_per_thread *pt = &context->pt[tsi];
- struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
- struct lws_vhost *vh = context->vhost_list;
- while (vh) {
- if (vh->lserv_wsi)
- ev_io_stop(ptpr->io_loop,
- &vh_to_priv_ev(vh)->w_accept.watcher);
- vh = vh->vhost_next;
- }
- /* static assets */
- ev_timer_stop(ptpr->io_loop, &ptpr->hrtimer);
- ev_idle_stop(ptpr->io_loop, &ptpr->idle);
- if (!pt->event_loop_foreign)
- ev_signal_stop(ptpr->io_loop, &ptpr->w_sigint.watcher);
- }
- static int
- elops_init_context_ev(struct lws_context *context,
- const struct lws_context_creation_info *info)
- {
- int n;
- context->eventlib_signal_cb = info->signal_cb;
- for (n = 0; n < context->count_threads; n++)
- pt_to_priv_ev(&context->pt[n])->w_sigint.context = context;
- return 0;
- }
- static int
- elops_accept_ev(struct lws *wsi)
- {
- struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi);
- int fd;
- lwsl_notice("%s\n", __func__);
- if (wsi->role_ops->file_handle)
- fd = wsi->desc.filefd;
- else
- fd = wsi->desc.sockfd;
- w->w_read.context = wsi->a.context;
- w->w_write.context = wsi->a.context;
- ev_io_init(&w->w_read.watcher, lws_accept_cb, fd, EV_READ);
- ev_io_init(&w->w_write.watcher, lws_accept_cb, fd, EV_WRITE);
- return 0;
- }
- static void
- elops_io_ev(struct lws *wsi, int flags)
- {
- struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
- struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
- struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi);
- lwsl_notice("%s: wsi %p %s flags 0x%x %p %d\n", __func__,
- wsi, wsi->role_ops->name, flags,
- ptpr->io_loop, pt->is_destroyed);
- if (!ptpr->io_loop || pt->is_destroyed)
- return;
- assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
- (flags & (LWS_EV_READ | LWS_EV_WRITE)));
- if (flags & LWS_EV_START) {
- if (flags & LWS_EV_WRITE)
- ev_io_start(ptpr->io_loop, &w->w_write.watcher);
- if (flags & LWS_EV_READ)
- ev_io_start(ptpr->io_loop, &w->w_read.watcher);
- } else {
- if (flags & LWS_EV_WRITE)
- ev_io_stop(ptpr->io_loop, &w->w_write.watcher);
- if (flags & LWS_EV_READ)
- ev_io_stop(ptpr->io_loop, &w->w_read.watcher);
- }
- if (pt->destroy_self)
- lws_context_destroy(pt->context);
- }
- static void
- elops_run_pt_ev(struct lws_context *context, int tsi)
- {
- if (pt_to_priv_ev(&context->pt[tsi])->io_loop)
- ev_run(pt_to_priv_ev(&context->pt[tsi])->io_loop, 0);
- }
- static int
- elops_destroy_context2_ev(struct lws_context *context)
- {
- struct lws_context_per_thread *pt;
- struct lws_pt_eventlibs_libev *ptpr;
- int n, m;
- lwsl_debug("%s\n", __func__);
- for (n = 0; n < context->count_threads; n++) {
- int budget = 1000;
- pt = &context->pt[n];
- ptpr = pt_to_priv_ev(pt);
- /* only for internal loops... */
- if (pt->event_loop_foreign || !ptpr->io_loop)
- continue;
- if (!context->finalize_destroy_after_internal_loops_stopped) {
- ev_break(ptpr->io_loop, EVBREAK_ONE);
- continue;
- }
- while (budget-- &&
- (m = ev_run(ptpr->io_loop, 0)))
- ;
- ev_loop_destroy(ptpr->io_loop);
- }
- return 0;
- }
- static int
- elops_init_vhost_listen_wsi_ev(struct lws *wsi)
- {
- struct lws_wsi_eventlibs_libev *w;
- int fd;
- if (!wsi) {
- assert(0);
- return 0;
- }
- w = wsi_to_priv_ev(wsi);
- w->w_read.context = wsi->a.context;
- w->w_write.context = wsi->a.context;
- if (wsi->role_ops->file_handle)
- fd = wsi->desc.filefd;
- else
- fd = wsi->desc.sockfd;
- ev_io_init(&w->w_read.watcher, lws_accept_cb, fd, EV_READ);
- //ev_io_init(&w->w_write.watcher, lws_accept_cb, fd, EV_WRITE);
- elops_io_ev(wsi, LWS_EV_START | LWS_EV_READ);
- return 0;
- }
- static void
- elops_destroy_wsi_ev(struct lws *wsi)
- {
- struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
- struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
- struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi);
- ev_io_stop(ptpr->io_loop, &w->w_read.watcher);
- ev_io_stop(ptpr->io_loop, &w->w_write.watcher);
- }
- static const struct lws_event_loop_ops event_loop_ops_ev = {
- /* name */ "libev",
- /* init_context */ elops_init_context_ev,
- /* destroy_context1 */ NULL,
- /* destroy_context2 */ elops_destroy_context2_ev,
- /* init_vhost_listen_wsi */ elops_init_vhost_listen_wsi_ev,
- /* init_pt */ elops_init_pt_ev,
- /* wsi_logical_close */ NULL,
- /* check_client_connect_ok */ NULL,
- /* close_handle_manually */ NULL,
- /* accept */ elops_accept_ev,
- /* io */ elops_io_ev,
- /* run_pt */ elops_run_pt_ev,
- /* destroy_pt */ elops_destroy_pt_ev,
- /* destroy wsi */ elops_destroy_wsi_ev,
- /* flags */ 0,
- /* evlib_size_ctx */ 0,
- /* evlib_size_pt */ sizeof(struct lws_pt_eventlibs_libev),
- /* evlib_size_vh */ sizeof(struct lws_vh_eventlibs_libev),
- /* evlib_size_wsi */ sizeof(struct lws_wsi_eventlibs_libev),
- };
- #if defined(LWS_WITH_EVLIB_PLUGINS)
- LWS_VISIBLE
- #endif
- const lws_plugin_evlib_t evlib_ev = {
- .hdr = {
- "libev event loop",
- "lws_evlib_plugin",
- LWS_PLUGIN_API_MAGIC
- },
- .ops = &event_loop_ops_ev
- };
|