unix-service.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. * libwebsockets - small server side websockets and web server implementation
  3. *
  4. * Copyright (C) 2010-2018 Andy Green <[email protected]>
  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. #define _GNU_SOURCE
  22. #include "core/private.h"
  23. int
  24. lws_poll_listen_fd(struct lws_pollfd *fd)
  25. {
  26. return poll(fd, 1, 0);
  27. }
  28. LWS_EXTERN int
  29. _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
  30. {
  31. volatile struct lws_foreign_thread_pollfd *ftp, *next;
  32. volatile struct lws_context_per_thread *vpt;
  33. struct lws_context_per_thread *pt;
  34. int n = -1, m, c;
  35. /* stay dead once we are dead */
  36. if (!context || !context->vhost_list)
  37. return 1;
  38. pt = &context->pt[tsi];
  39. vpt = (volatile struct lws_context_per_thread *)pt;
  40. lws_stats_atomic_bump(context, pt, LWSSTATS_C_SERVICE_ENTRY, 1);
  41. if (timeout_ms < 0)
  42. goto faked_service;
  43. if (context->event_loop_ops->run_pt)
  44. context->event_loop_ops->run_pt(context, tsi);
  45. if (!pt->service_tid_detected) {
  46. struct lws _lws;
  47. memset(&_lws, 0, sizeof(_lws));
  48. _lws.context = context;
  49. pt->service_tid =
  50. context->vhost_list->protocols[0].callback(
  51. &_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
  52. pt->service_tid_detected = 1;
  53. }
  54. /*
  55. * is there anybody with pending stuff that needs service forcing?
  56. */
  57. if (!lws_service_adjust_timeout(context, 1, tsi)) {
  58. /* -1 timeout means just do forced service */
  59. _lws_plat_service_tsi(context, -1, pt->tid);
  60. /* still somebody left who wants forced service? */
  61. if (!lws_service_adjust_timeout(context, 1, pt->tid))
  62. /* yes... come back again quickly */
  63. timeout_ms = 0;
  64. }
  65. if (timeout_ms) {
  66. lws_pt_lock(pt, __func__);
  67. /* don't stay in poll wait longer than next hr timeout */
  68. lws_usec_t t = __lws_hrtimer_service(pt);
  69. if ((lws_usec_t)timeout_ms * 1000 > t)
  70. timeout_ms = t / 1000;
  71. lws_pt_unlock(pt);
  72. }
  73. vpt->inside_poll = 1;
  74. lws_memory_barrier();
  75. n = poll(pt->fds, pt->fds_count, timeout_ms);
  76. vpt->inside_poll = 0;
  77. lws_memory_barrier();
  78. /* Collision will be rare and brief. Just spin until it completes */
  79. while (vpt->foreign_spinlock)
  80. ;
  81. /*
  82. * At this point we are not inside a foreign thread pollfd change,
  83. * and we have marked ourselves as outside the poll() wait. So we
  84. * are the only guys that can modify the lws_foreign_thread_pollfd
  85. * list on the pt. Drain the list and apply the changes to the
  86. * affected pollfds in the correct order.
  87. */
  88. lws_pt_lock(pt, __func__);
  89. ftp = vpt->foreign_pfd_list;
  90. //lwsl_notice("cleared list %p\n", ftp);
  91. while (ftp) {
  92. struct lws *wsi;
  93. struct lws_pollfd *pfd;
  94. next = ftp->next;
  95. pfd = &vpt->fds[ftp->fd_index];
  96. if (lws_socket_is_valid(pfd->fd)) {
  97. wsi = wsi_from_fd(context, pfd->fd);
  98. if (wsi)
  99. __lws_change_pollfd(wsi, ftp->_and, ftp->_or);
  100. }
  101. lws_free((void *)ftp);
  102. ftp = next;
  103. }
  104. vpt->foreign_pfd_list = NULL;
  105. lws_memory_barrier();
  106. /* we have come out of a poll wait... check the hrtimer list */
  107. __lws_hrtimer_service(pt);
  108. lws_pt_unlock(pt);
  109. m = 0;
  110. #if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
  111. m |= !!pt->ws.rx_draining_ext_list;
  112. #endif
  113. if (pt->context->tls_ops &&
  114. pt->context->tls_ops->fake_POLLIN_for_buffered)
  115. m |= pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
  116. if (!m && !n) { /* nothing to do */
  117. lws_service_fd_tsi(context, NULL, tsi);
  118. lws_service_do_ripe_rxflow(pt);
  119. return 0;
  120. }
  121. faked_service:
  122. m = lws_service_flag_pending(context, tsi);
  123. if (m)
  124. c = -1; /* unknown limit */
  125. else
  126. if (n < 0) {
  127. if (LWS_ERRNO != LWS_EINTR)
  128. return -1;
  129. return 0;
  130. } else
  131. c = n;
  132. /* any socket with events to service? */
  133. for (n = 0; n < (int)pt->fds_count && c; n++) {
  134. if (!pt->fds[n].revents)
  135. continue;
  136. c--;
  137. m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
  138. if (m < 0) {
  139. lwsl_err("%s: lws_service_fd_tsi returned %d\n",
  140. __func__, m);
  141. return -1;
  142. }
  143. /* if something closed, retry this slot */
  144. if (m)
  145. n--;
  146. }
  147. lws_service_do_ripe_rxflow(pt);
  148. return 0;
  149. }
  150. int
  151. lws_plat_check_connection_error(struct lws *wsi)
  152. {
  153. return 0;
  154. }
  155. int
  156. lws_plat_service(struct lws_context *context, int timeout_ms)
  157. {
  158. return _lws_plat_service_tsi(context, timeout_ms, 0);
  159. }
  160. void
  161. lws_plat_service_periodic(struct lws_context *context)
  162. {
  163. /* if our parent went down, don't linger around */
  164. if (context->started_with_parent &&
  165. kill(context->started_with_parent, 0) < 0)
  166. kill(getpid(), SIGTERM);
  167. }