virtualx-engine/thirdparty/libwebsockets/lib/plat/unix/unix-service.c
2019-03-06 02:02:52 +01:00

204 lines
5 KiB
C

/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
*
* 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);
}