1/* 2 * libwebsockets - small server side websockets and web server implementation 3 * 4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 */ 24 25#if !defined(_GNU_SOURCE) 26#define _GNU_SOURCE 27#endif 28#include "private-lib-core.h" 29 30int 31lws_poll_listen_fd(struct lws_pollfd *fd) 32{ 33 return poll(fd, 1, 0); 34} 35 36int 37_lws_plat_service_forced_tsi(struct lws_context *context, int tsi) 38{ 39 struct lws_context_per_thread *pt = &context->pt[tsi]; 40 int m, n, r; 41 42 r = lws_service_flag_pending(context, tsi); 43 44 /* any socket with events to service? */ 45 for (n = 0; n < (int)pt->fds_count; n++) { 46 lws_sockfd_type fd = pt->fds[n].fd; 47 48 if (!pt->fds[n].revents) 49 continue; 50 51 m = lws_service_fd_tsi(context, &pt->fds[n], tsi); 52 if (m < 0) { 53 lwsl_err("%s: lws_service_fd_tsi returned %d\n", 54 __func__, m); 55 return -1; 56 } 57 58 /* if something closed, retry this slot since may have been 59 * swapped with end fd */ 60 if (m && pt->fds[n].fd != fd) 61 n--; 62 } 63 64 lws_service_do_ripe_rxflow(pt); 65 66 return r; 67} 68 69#define LWS_POLL_WAIT_LIMIT 2000000000 70 71int 72_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi) 73{ 74 volatile struct lws_foreign_thread_pollfd *ftp, *next; 75 volatile struct lws_context_per_thread *vpt; 76 struct lws_context_per_thread *pt; 77 lws_usec_t timeout_us, us; 78#if defined(LWS_WITH_SYS_METRICS) 79 lws_usec_t a, b; 80#endif 81 int n; 82#if (defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)) || defined(LWS_WITH_TLS) 83 int m; 84#endif 85 86 /* stay dead once we are dead */ 87 88 if (!context) 89 return 1; 90 91#if defined(LWS_WITH_SYS_METRICS) 92 b = 93#endif 94 us = lws_now_usecs(); 95 96 pt = &context->pt[tsi]; 97 vpt = (volatile struct lws_context_per_thread *)pt; 98 99 if (timeout_ms < 0) 100 timeout_ms = 0; 101 else 102 /* force a default timeout of 23 days */ 103 timeout_ms = LWS_POLL_WAIT_LIMIT; 104 timeout_us = ((lws_usec_t)timeout_ms) * LWS_US_PER_MS; 105 106 if (context->event_loop_ops->run_pt) 107 context->event_loop_ops->run_pt(context, tsi); 108 109 if (!pt->service_tid_detected && context->vhost_list) { 110 lws_fakewsi_def_plwsa(pt); 111 112 lws_fakewsi_prep_plwsa_ctx(context); 113 114 pt->service_tid = context->vhost_list->protocols[0].callback( 115 (struct lws *)plwsa, 116 LWS_CALLBACK_GET_THREAD_ID, 117 NULL, NULL, 0); 118 pt->service_tid_detected = 1; 119 } 120 121 lws_pt_lock(pt, __func__); 122 /* 123 * service ripe scheduled events, and limit wait to next expected one 124 */ 125 us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, us); 126 if (us && us < timeout_us) 127 /* 128 * If something wants zero wait, that's OK, but if the next sul 129 * coming ripe is an interval less than our wait resolution, 130 * bump it to be the wait resolution. 131 */ 132 timeout_us = us < context->us_wait_resolution ? 133 context->us_wait_resolution : us; 134 135 lws_pt_unlock(pt); 136 137 /* 138 * is there anybody with pending stuff that needs service forcing? 139 */ 140 if (!lws_service_adjust_timeout(context, 1, tsi)) 141 timeout_us = 0; 142 143 /* ensure we don't wrap at 2^31 with poll()'s signed int ms */ 144 145 timeout_us /= LWS_US_PER_MS; /* ms now */ 146 147#if defined(LWS_WITH_SYS_METRICS) 148 a = lws_now_usecs() - b; 149#endif 150 vpt->inside_poll = 1; 151 lws_memory_barrier(); 152 n = poll(pt->fds, pt->fds_count, (int)timeout_us /* ms now */ ); 153 vpt->inside_poll = 0; 154 lws_memory_barrier(); 155 156#if defined(LWS_WITH_SYS_METRICS) 157 b = lws_now_usecs(); 158#endif 159 /* Collision will be rare and brief. Spin until it completes */ 160 while (vpt->foreign_spinlock) 161 ; 162 163 /* 164 * At this point we are not inside a foreign thread pollfd 165 * change, and we have marked ourselves as outside the poll() 166 * wait. So we are the only guys that can modify the 167 * lws_foreign_thread_pollfd list on the pt. Drain the list 168 * and apply the changes to the affected pollfds in the correct 169 * order. 170 */ 171 172 lws_pt_lock(pt, __func__); 173 174 ftp = vpt->foreign_pfd_list; 175 //lwsl_notice("cleared list %p\n", ftp); 176 while (ftp) { 177 struct lws *wsi; 178 struct lws_pollfd *pfd; 179 180 next = ftp->next; 181 pfd = &vpt->fds[ftp->fd_index]; 182 if (lws_socket_is_valid(pfd->fd)) { 183 wsi = wsi_from_fd(context, pfd->fd); 184 if (wsi) 185 __lws_change_pollfd(wsi, ftp->_and, 186 ftp->_or); 187 } 188 lws_free((void *)ftp); 189 ftp = next; 190 } 191 vpt->foreign_pfd_list = NULL; 192 lws_memory_barrier(); 193 194 lws_pt_unlock(pt); 195 196#if (defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)) || defined(LWS_WITH_TLS) 197 m = 0; 198#endif 199#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS) 200 m |= !!pt->ws.rx_draining_ext_list; 201#endif 202 203#if defined(LWS_WITH_TLS) 204 if (pt->context->tls_ops && 205 pt->context->tls_ops->fake_POLLIN_for_buffered) 206 m |= pt->context->tls_ops->fake_POLLIN_for_buffered(pt); 207#endif 208 209 if ( 210#if (defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)) || defined(LWS_WITH_TLS) 211 !m && 212#endif 213 !n) /* nothing to do */ 214 lws_service_do_ripe_rxflow(pt); 215 else 216 if (_lws_plat_service_forced_tsi(context, tsi) < 0) 217 return -1; 218 219#if defined(LWS_WITH_SYS_METRICS) 220 lws_metric_event(context->mt_service, METRES_GO, 221 (u_mt_t) (a + (lws_now_usecs() - b))); 222#endif 223 224 if (pt->destroy_self) { 225 lws_context_destroy(pt->context); 226 return -1; 227 } 228 229 return 0; 230} 231 232int 233lws_plat_service(struct lws_context *context, int timeout_ms) 234{ 235 return _lws_plat_service_tsi(context, timeout_ms, 0); 236} 237