port.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /* Licensed to the Apache Software Foundation (ASF) under one or more
  2. * contributor license agreements. See the NOTICE file distributed with
  3. * this work for additional information regarding copyright ownership.
  4. * The ASF licenses this file to You under the Apache License, Version 2.0
  5. * (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "apr_arch_poll_private.h"
  17. #ifdef POLLSET_USES_PORT
  18. static apr_int16_t get_event(apr_int16_t event)
  19. {
  20. apr_int16_t rv = 0;
  21. if (event & APR_POLLIN)
  22. rv |= POLLIN;
  23. if (event & APR_POLLPRI)
  24. rv |= POLLPRI;
  25. if (event & APR_POLLOUT)
  26. rv |= POLLOUT;
  27. if (event & APR_POLLERR)
  28. rv |= POLLERR;
  29. if (event & APR_POLLHUP)
  30. rv |= POLLHUP;
  31. if (event & APR_POLLNVAL)
  32. rv |= POLLNVAL;
  33. return rv;
  34. }
  35. static apr_int16_t get_revent(apr_int16_t event)
  36. {
  37. apr_int16_t rv = 0;
  38. if (event & POLLIN)
  39. rv |= APR_POLLIN;
  40. if (event & POLLPRI)
  41. rv |= APR_POLLPRI;
  42. if (event & POLLOUT)
  43. rv |= APR_POLLOUT;
  44. if (event & POLLERR)
  45. rv |= APR_POLLERR;
  46. if (event & POLLHUP)
  47. rv |= APR_POLLHUP;
  48. if (event & POLLNVAL)
  49. rv |= APR_POLLNVAL;
  50. return rv;
  51. }
  52. struct apr_pollset_t
  53. {
  54. apr_pool_t *pool;
  55. apr_uint32_t nelts;
  56. apr_uint32_t nalloc;
  57. int port_fd;
  58. port_event_t *port_set;
  59. apr_pollfd_t *result_set;
  60. apr_uint32_t flags;
  61. #if APR_HAS_THREADS
  62. /* A thread mutex to protect operations on the rings */
  63. apr_thread_mutex_t *ring_lock;
  64. #endif
  65. /* A ring containing all of the pollfd_t that are active */
  66. APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring;
  67. APR_RING_HEAD(pfd_add_ring_t, pfd_elem_t) add_ring;
  68. /* A ring of pollfd_t that have been used, and then _remove'd */
  69. APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring;
  70. /* A ring of pollfd_t where rings that have been _remove'd but
  71. might still be inside a _poll */
  72. APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring;
  73. };
  74. static apr_status_t backend_cleanup(void *p_)
  75. {
  76. apr_pollset_t *pollset = (apr_pollset_t *) p_;
  77. close(pollset->port_fd);
  78. return APR_SUCCESS;
  79. }
  80. APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
  81. apr_uint32_t size,
  82. apr_pool_t *p,
  83. apr_uint32_t flags)
  84. {
  85. apr_status_t rv = APR_SUCCESS;
  86. *pollset = apr_palloc(p, sizeof(**pollset));
  87. #if APR_HAS_THREADS
  88. if (flags & APR_POLLSET_THREADSAFE &&
  89. ((rv = apr_thread_mutex_create(&(*pollset)->ring_lock,
  90. APR_THREAD_MUTEX_DEFAULT,
  91. p) != APR_SUCCESS))) {
  92. *pollset = NULL;
  93. return rv;
  94. }
  95. #else
  96. if (flags & APR_POLLSET_THREADSAFE) {
  97. *pollset = NULL;
  98. return APR_ENOTIMPL;
  99. }
  100. #endif
  101. (*pollset)->nelts = 0;
  102. (*pollset)->nalloc = size;
  103. (*pollset)->flags = flags;
  104. (*pollset)->pool = p;
  105. (*pollset)->port_set = apr_palloc(p, size * sizeof(port_event_t));
  106. (*pollset)->port_fd = port_create();
  107. if ((*pollset)->port_fd < 0) {
  108. return APR_ENOMEM;
  109. }
  110. apr_pool_cleanup_register(p, (void *) (*pollset), backend_cleanup,
  111. apr_pool_cleanup_null);
  112. (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
  113. APR_RING_INIT(&(*pollset)->query_ring, pfd_elem_t, link);
  114. APR_RING_INIT(&(*pollset)->add_ring, pfd_elem_t, link);
  115. APR_RING_INIT(&(*pollset)->free_ring, pfd_elem_t, link);
  116. APR_RING_INIT(&(*pollset)->dead_ring, pfd_elem_t, link);
  117. return rv;
  118. }
  119. APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset)
  120. {
  121. return apr_pool_cleanup_run(pollset->pool, pollset, backend_cleanup);
  122. }
  123. APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
  124. const apr_pollfd_t *descriptor)
  125. {
  126. apr_os_sock_t fd;
  127. pfd_elem_t *elem;
  128. int res;
  129. apr_status_t rv = APR_SUCCESS;
  130. pollset_lock_rings();
  131. if (!APR_RING_EMPTY(&(pollset->free_ring), pfd_elem_t, link)) {
  132. elem = APR_RING_FIRST(&(pollset->free_ring));
  133. APR_RING_REMOVE(elem, link);
  134. }
  135. else {
  136. elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t));
  137. APR_RING_ELEM_INIT(elem, link);
  138. }
  139. elem->pfd = *descriptor;
  140. if (descriptor->desc_type == APR_POLL_SOCKET) {
  141. fd = descriptor->desc.s->socketdes;
  142. }
  143. else {
  144. fd = descriptor->desc.f->filedes;
  145. }
  146. res = port_associate(pollset->port_fd, PORT_SOURCE_FD, fd,
  147. get_event(descriptor->reqevents), (void *)elem);
  148. if (res < 0) {
  149. rv = APR_ENOMEM;
  150. APR_RING_INSERT_TAIL(&(pollset->free_ring), elem, pfd_elem_t, link);
  151. }
  152. else {
  153. pollset->nelts++;
  154. APR_RING_INSERT_TAIL(&(pollset->query_ring), elem, pfd_elem_t, link);
  155. }
  156. pollset_unlock_rings();
  157. return rv;
  158. }
  159. APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset,
  160. const apr_pollfd_t *descriptor)
  161. {
  162. apr_os_sock_t fd;
  163. pfd_elem_t *ep;
  164. apr_status_t rv = APR_SUCCESS;
  165. int res;
  166. pollset_lock_rings();
  167. if (descriptor->desc_type == APR_POLL_SOCKET) {
  168. fd = descriptor->desc.s->socketdes;
  169. }
  170. else {
  171. fd = descriptor->desc.f->filedes;
  172. }
  173. res = port_dissociate(pollset->port_fd, PORT_SOURCE_FD, fd);
  174. if (res < 0) {
  175. rv = APR_NOTFOUND;
  176. }
  177. if (!APR_RING_EMPTY(&(pollset->query_ring), pfd_elem_t, link)) {
  178. for (ep = APR_RING_FIRST(&(pollset->query_ring));
  179. ep != APR_RING_SENTINEL(&(pollset->query_ring),
  180. pfd_elem_t, link);
  181. ep = APR_RING_NEXT(ep, link)) {
  182. if (descriptor->desc.s == ep->pfd.desc.s) {
  183. APR_RING_REMOVE(ep, link);
  184. APR_RING_INSERT_TAIL(&(pollset->dead_ring),
  185. ep, pfd_elem_t, link);
  186. break;
  187. }
  188. }
  189. }
  190. if (!APR_RING_EMPTY(&(pollset->add_ring), pfd_elem_t, link)) {
  191. for (ep = APR_RING_FIRST(&(pollset->add_ring));
  192. ep != APR_RING_SENTINEL(&(pollset->add_ring),
  193. pfd_elem_t, link);
  194. ep = APR_RING_NEXT(ep, link)) {
  195. if (descriptor->desc.s == ep->pfd.desc.s) {
  196. APR_RING_REMOVE(ep, link);
  197. APR_RING_INSERT_TAIL(&(pollset->dead_ring),
  198. ep, pfd_elem_t, link);
  199. break;
  200. }
  201. }
  202. }
  203. pollset_unlock_rings();
  204. return rv;
  205. }
  206. APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
  207. apr_interval_time_t timeout,
  208. apr_int32_t *num,
  209. const apr_pollfd_t **descriptors)
  210. {
  211. apr_os_sock_t fd;
  212. int ret, i;
  213. unsigned int nget;
  214. pfd_elem_t *ep;
  215. struct timespec tv, *tvptr;
  216. apr_status_t rv = APR_SUCCESS;
  217. if (timeout < 0) {
  218. tvptr = NULL;
  219. }
  220. else {
  221. tv.tv_sec = (long) apr_time_sec(timeout);
  222. tv.tv_nsec = (long) apr_time_msec(timeout);
  223. tvptr = &tv;
  224. }
  225. nget = 1;
  226. pollset_lock_rings();
  227. while (!APR_RING_EMPTY(&(pollset->add_ring), pfd_elem_t, link)) {
  228. ep = APR_RING_FIRST(&(pollset->add_ring));
  229. APR_RING_REMOVE(ep, link);
  230. if (ep->pfd.desc_type == APR_POLL_SOCKET) {
  231. fd = ep->pfd.desc.s->socketdes;
  232. }
  233. else {
  234. fd = ep->pfd.desc.f->filedes;
  235. }
  236. port_associate(pollset->port_fd, PORT_SOURCE_FD,
  237. fd, get_event(ep->pfd.reqevents), ep);
  238. APR_RING_INSERT_TAIL(&(pollset->query_ring), ep, pfd_elem_t, link);
  239. }
  240. pollset_unlock_rings();
  241. ret = port_getn(pollset->port_fd, pollset->port_set, pollset->nalloc,
  242. &nget, tvptr);
  243. (*num) = nget;
  244. if (ret == -1) {
  245. (*num) = 0;
  246. if (errno == ETIME || errno == EINTR) {
  247. rv = APR_TIMEUP;
  248. }
  249. else {
  250. rv = APR_EGENERAL;
  251. }
  252. }
  253. else if (nget == 0) {
  254. rv = APR_TIMEUP;
  255. }
  256. else {
  257. pollset_lock_rings();
  258. for (i = 0; i < nget; i++) {
  259. pollset->result_set[i] =
  260. (((pfd_elem_t*)(pollset->port_set[i].portev_user))->pfd);
  261. pollset->result_set[i].rtnevents =
  262. get_revent(pollset->port_set[i].portev_events);
  263. APR_RING_REMOVE((pfd_elem_t*)pollset->port_set[i].portev_user, link);
  264. APR_RING_INSERT_TAIL(&(pollset->add_ring),
  265. (pfd_elem_t*)pollset->port_set[i].portev_user,
  266. pfd_elem_t, link);
  267. }
  268. pollset_unlock_rings();
  269. if (descriptors) {
  270. *descriptors = pollset->result_set;
  271. }
  272. }
  273. pollset_lock_rings();
  274. /* Shift all PFDs in the Dead Ring to be Free Ring */
  275. APR_RING_CONCAT(&(pollset->free_ring), &(pollset->dead_ring), pfd_elem_t, link);
  276. pollset_unlock_rings();
  277. return rv;
  278. }
  279. #endif /* POLLSET_USES_PORT */