123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- /*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2018 Andy Green <[email protected]>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
- #define _GNU_SOURCE
- #include "core/private.h"
- int
- lws_poll_listen_fd(struct lws_pollfd *fd)
- {
- return poll(fd, 1, 0);
- }
- LWS_EXTERN int
- _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
- {
- volatile struct lws_foreign_thread_pollfd *ftp, *next;
- volatile struct lws_context_per_thread *vpt;
- struct lws_context_per_thread *pt;
- int n = -1, m, c;
- /* stay dead once we are dead */
- if (!context || !context->vhost_list)
- return 1;
- pt = &context->pt[tsi];
- vpt = (volatile struct lws_context_per_thread *)pt;
- lws_stats_atomic_bump(context, pt, LWSSTATS_C_SERVICE_ENTRY, 1);
- if (timeout_ms < 0)
- goto faked_service;
- if (context->event_loop_ops->run_pt)
- context->event_loop_ops->run_pt(context, tsi);
- if (!pt->service_tid_detected) {
- struct lws _lws;
- memset(&_lws, 0, sizeof(_lws));
- _lws.context = context;
- pt->service_tid =
- context->vhost_list->protocols[0].callback(
- &_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
- pt->service_tid_detected = 1;
- }
- /*
- * is there anybody with pending stuff that needs service forcing?
- */
- if (!lws_service_adjust_timeout(context, 1, tsi)) {
- /* -1 timeout means just do forced service */
- _lws_plat_service_tsi(context, -1, pt->tid);
- /* still somebody left who wants forced service? */
- if (!lws_service_adjust_timeout(context, 1, pt->tid))
- /* yes... come back again quickly */
- timeout_ms = 0;
- }
- if (timeout_ms) {
- lws_pt_lock(pt, __func__);
- /* don't stay in poll wait longer than next hr timeout */
- lws_usec_t t = __lws_hrtimer_service(pt);
- if ((lws_usec_t)timeout_ms * 1000 > t)
- timeout_ms = t / 1000;
- lws_pt_unlock(pt);
- }
- vpt->inside_poll = 1;
- lws_memory_barrier();
- n = poll(pt->fds, pt->fds_count, timeout_ms);
- vpt->inside_poll = 0;
- lws_memory_barrier();
- /* Collision will be rare and brief. Just spin until it completes */
- while (vpt->foreign_spinlock)
- ;
- /*
- * At this point we are not inside a foreign thread pollfd change,
- * and we have marked ourselves as outside the poll() wait. So we
- * are the only guys that can modify the lws_foreign_thread_pollfd
- * list on the pt. Drain the list and apply the changes to the
- * affected pollfds in the correct order.
- */
- lws_pt_lock(pt, __func__);
- ftp = vpt->foreign_pfd_list;
- //lwsl_notice("cleared list %p\n", ftp);
- while (ftp) {
- struct lws *wsi;
- struct lws_pollfd *pfd;
- next = ftp->next;
- pfd = &vpt->fds[ftp->fd_index];
- if (lws_socket_is_valid(pfd->fd)) {
- wsi = wsi_from_fd(context, pfd->fd);
- if (wsi)
- __lws_change_pollfd(wsi, ftp->_and, ftp->_or);
- }
- lws_free((void *)ftp);
- ftp = next;
- }
- vpt->foreign_pfd_list = NULL;
- lws_memory_barrier();
- /* we have come out of a poll wait... check the hrtimer list */
- __lws_hrtimer_service(pt);
- lws_pt_unlock(pt);
- m = 0;
- #if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
- m |= !!pt->ws.rx_draining_ext_list;
- #endif
- if (pt->context->tls_ops &&
- pt->context->tls_ops->fake_POLLIN_for_buffered)
- m |= pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
- if (!m && !n) { /* nothing to do */
- lws_service_fd_tsi(context, NULL, tsi);
- lws_service_do_ripe_rxflow(pt);
- return 0;
- }
- faked_service:
- m = lws_service_flag_pending(context, tsi);
- if (m)
- c = -1; /* unknown limit */
- else
- if (n < 0) {
- if (LWS_ERRNO != LWS_EINTR)
- return -1;
- return 0;
- } else
- c = n;
- /* any socket with events to service? */
- for (n = 0; n < (int)pt->fds_count && c; n++) {
- if (!pt->fds[n].revents)
- continue;
- c--;
- m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
- if (m < 0) {
- lwsl_err("%s: lws_service_fd_tsi returned %d\n",
- __func__, m);
- return -1;
- }
- /* if something closed, retry this slot */
- if (m)
- n--;
- }
- lws_service_do_ripe_rxflow(pt);
- return 0;
- }
- int
- lws_plat_check_connection_error(struct lws *wsi)
- {
- return 0;
- }
- int
- lws_plat_service(struct lws_context *context, int timeout_ms)
- {
- return _lws_plat_service_tsi(context, timeout_ms, 0);
- }
- void
- lws_plat_service_periodic(struct lws_context *context)
- {
- /* if our parent went down, don't linger around */
- if (context->started_with_parent &&
- kill(context->started_with_parent, 0) < 0)
- kill(getpid(), SIGTERM);
- }
|