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 17#include "apr.h" 18#include "apr_poll.h" 19#include "apr_time.h" 20#include "apr_portable.h" 21#include "apr_arch_file_io.h" 22#include "apr_arch_networkio.h" 23#include "apr_arch_poll_private.h" 24#include "apr_arch_inherit.h" 25 26#ifdef HAVE_KQUEUE 27 28static apr_int16_t get_kqueue_revent(apr_int16_t event, apr_int16_t flags) 29{ 30 apr_int16_t rv = 0; 31 32 if (event == EVFILT_READ) 33 rv |= APR_POLLIN; 34 else if (event == EVFILT_WRITE) 35 rv |= APR_POLLOUT; 36 if (flags & EV_EOF) 37 rv |= APR_POLLHUP; 38 /* APR_POLLPRI, APR_POLLERR, and APR_POLLNVAL are not handled by this 39 * implementation. 40 * TODO: See if EV_ERROR + certain system errors in the returned data field 41 * should map to APR_POLLNVAL. 42 */ 43 return rv; 44} 45 46struct apr_pollset_private_t 47{ 48 int kqueue_fd; 49 struct kevent kevent; 50 apr_uint32_t setsize; 51 struct kevent *ke_set; 52 apr_pollfd_t *result_set; 53#if APR_HAS_THREADS 54 /* A thread mutex to protect operations on the rings */ 55 apr_thread_mutex_t *ring_lock; 56#endif 57 /* A ring containing all of the pollfd_t that are active */ 58 APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring; 59 /* A ring of pollfd_t that have been used, and then _remove'd */ 60 APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring; 61 /* A ring of pollfd_t where rings that have been _remove'd but 62 might still be inside a _poll */ 63 APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring; 64}; 65 66static apr_status_t impl_pollset_cleanup(apr_pollset_t *pollset) 67{ 68 close(pollset->p->kqueue_fd); 69 return APR_SUCCESS; 70} 71 72static apr_status_t impl_pollset_create(apr_pollset_t *pollset, 73 apr_uint32_t size, 74 apr_pool_t *p, 75 apr_uint32_t flags) 76{ 77 apr_status_t rv; 78 pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); 79#if APR_HAS_THREADS 80 if (flags & APR_POLLSET_THREADSAFE && 81 ((rv = apr_thread_mutex_create(&pollset->p->ring_lock, 82 APR_THREAD_MUTEX_DEFAULT, 83 p)) != APR_SUCCESS)) { 84 pollset->p = NULL; 85 return rv; 86 } 87#else 88 if (flags & APR_POLLSET_THREADSAFE) { 89 pollset->p = NULL; 90 return APR_ENOTIMPL; 91 } 92#endif 93 94 /* POLLIN and POLLOUT are represented in different returned 95 * events, so we need 2 entries per descriptor in the result set, 96 * both for what is returned by kevent() and what is returned to 97 * the caller of apr_pollset_poll() (since it doesn't spend the 98 * CPU to coalesce separate APR_POLLIN and APR_POLLOUT events 99 * for the same descriptor) 100 */ 101 pollset->p->setsize = 2 * size; 102 103 pollset->p->ke_set = 104 (struct kevent *) apr_palloc(p, pollset->p->setsize * sizeof(struct kevent)); 105 106 memset(pollset->p->ke_set, 0, pollset->p->setsize * sizeof(struct kevent)); 107 108 pollset->p->kqueue_fd = kqueue(); 109 110 if (pollset->p->kqueue_fd == -1) { 111 pollset->p = NULL; 112 return apr_get_netos_error(); 113 } 114 115 { 116 int flags; 117 118 if ((flags = fcntl(pollset->p->kqueue_fd, F_GETFD)) == -1) 119 return errno; 120 121 flags |= FD_CLOEXEC; 122 if (fcntl(pollset->p->kqueue_fd, F_SETFD, flags) == -1) 123 return errno; 124 } 125 126 pollset->p->result_set = apr_palloc(p, pollset->p->setsize * sizeof(apr_pollfd_t)); 127 128 APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); 129 APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link); 130 APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link); 131 132 return APR_SUCCESS; 133} 134 135static apr_status_t impl_pollset_add(apr_pollset_t *pollset, 136 const apr_pollfd_t *descriptor) 137{ 138 apr_os_sock_t fd; 139 pfd_elem_t *elem; 140 apr_status_t rv = APR_SUCCESS; 141 142 pollset_lock_rings(); 143 144 if (!APR_RING_EMPTY(&(pollset->p->free_ring), pfd_elem_t, link)) { 145 elem = APR_RING_FIRST(&(pollset->p->free_ring)); 146 APR_RING_REMOVE(elem, link); 147 } 148 else { 149 elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t)); 150 APR_RING_ELEM_INIT(elem, link); 151 } 152 elem->pfd = *descriptor; 153 154 if (descriptor->desc_type == APR_POLL_SOCKET) { 155 fd = descriptor->desc.s->socketdes; 156 } 157 else { 158 fd = descriptor->desc.f->filedes; 159 } 160 161 if (descriptor->reqevents & APR_POLLIN) { 162 EV_SET(&pollset->p->kevent, fd, EVFILT_READ, EV_ADD, 0, 0, elem); 163 164 if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, 165 NULL) == -1) { 166 rv = apr_get_netos_error(); 167 } 168 } 169 170 if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) { 171 EV_SET(&pollset->p->kevent, fd, EVFILT_WRITE, EV_ADD, 0, 0, elem); 172 173 if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, 174 NULL) == -1) { 175 rv = apr_get_netos_error(); 176 } 177 } 178 179 if (rv == APR_SUCCESS) { 180 APR_RING_INSERT_TAIL(&(pollset->p->query_ring), elem, pfd_elem_t, link); 181 } 182 else { 183 APR_RING_INSERT_TAIL(&(pollset->p->free_ring), elem, pfd_elem_t, link); 184 } 185 186 pollset_unlock_rings(); 187 188 return rv; 189} 190 191static apr_status_t impl_pollset_remove(apr_pollset_t *pollset, 192 const apr_pollfd_t *descriptor) 193{ 194 pfd_elem_t *ep; 195 apr_status_t rv; 196 apr_os_sock_t fd; 197 198 pollset_lock_rings(); 199 200 if (descriptor->desc_type == APR_POLL_SOCKET) { 201 fd = descriptor->desc.s->socketdes; 202 } 203 else { 204 fd = descriptor->desc.f->filedes; 205 } 206 207 rv = APR_NOTFOUND; /* unless at least one of the specified conditions is */ 208 if (descriptor->reqevents & APR_POLLIN) { 209 EV_SET(&pollset->p->kevent, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); 210 211 if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, 212 NULL) != -1) { 213 rv = APR_SUCCESS; 214 } 215 } 216 217 if (descriptor->reqevents & APR_POLLOUT) { 218 EV_SET(&pollset->p->kevent, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 219 220 if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, 221 NULL) != -1) { 222 rv = APR_SUCCESS; 223 } 224 } 225 226 for (ep = APR_RING_FIRST(&(pollset->p->query_ring)); 227 ep != APR_RING_SENTINEL(&(pollset->p->query_ring), 228 pfd_elem_t, link); 229 ep = APR_RING_NEXT(ep, link)) { 230 231 if (descriptor->desc.s == ep->pfd.desc.s) { 232 APR_RING_REMOVE(ep, link); 233 APR_RING_INSERT_TAIL(&(pollset->p->dead_ring), 234 ep, pfd_elem_t, link); 235 break; 236 } 237 } 238 239 pollset_unlock_rings(); 240 241 return rv; 242} 243 244static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, 245 apr_interval_time_t timeout, 246 apr_int32_t *num, 247 const apr_pollfd_t **descriptors) 248{ 249 int ret, i, j; 250 struct timespec tv, *tvptr; 251 apr_status_t rv = APR_SUCCESS; 252 apr_pollfd_t fd; 253 254 if (timeout < 0) { 255 tvptr = NULL; 256 } 257 else { 258 tv.tv_sec = (long) apr_time_sec(timeout); 259 tv.tv_nsec = (long) apr_time_usec(timeout) * 1000; 260 tvptr = &tv; 261 } 262 263 ret = kevent(pollset->p->kqueue_fd, NULL, 0, pollset->p->ke_set, 264 pollset->p->setsize, tvptr); 265 (*num) = ret; 266 if (ret < 0) { 267 rv = apr_get_netos_error(); 268 } 269 else if (ret == 0) { 270 rv = APR_TIMEUP; 271 } 272 else { 273 for (i = 0, j = 0; i < ret; i++) { 274 fd = (((pfd_elem_t*)(pollset->p->ke_set[i].udata))->pfd); 275 if ((pollset->flags & APR_POLLSET_WAKEABLE) && 276 fd.desc_type == APR_POLL_FILE && 277 fd.desc.f == pollset->wakeup_pipe[0]) { 278 apr_pollset_drain_wakeup_pipe(pollset); 279 rv = APR_EINTR; 280 } 281 else { 282 pollset->p->result_set[j] = fd; 283 pollset->p->result_set[j].rtnevents = 284 get_kqueue_revent(pollset->p->ke_set[i].filter, 285 pollset->p->ke_set[i].flags); 286 j++; 287 } 288 } 289 if ((*num = j)) { /* any event besides wakeup pipe? */ 290 rv = APR_SUCCESS; 291 if (descriptors) { 292 *descriptors = pollset->p->result_set; 293 } 294 } 295 } 296 297 298 pollset_lock_rings(); 299 300 /* Shift all PFDs in the Dead Ring to the Free Ring */ 301 APR_RING_CONCAT(&(pollset->p->free_ring), &(pollset->p->dead_ring), 302 pfd_elem_t, link); 303 304 pollset_unlock_rings(); 305 306 return rv; 307} 308 309static apr_pollset_provider_t impl = { 310 impl_pollset_create, 311 impl_pollset_add, 312 impl_pollset_remove, 313 impl_pollset_poll, 314 impl_pollset_cleanup, 315 "kqueue" 316}; 317 318apr_pollset_provider_t *apr_pollset_provider_kqueue = &impl; 319 320static apr_status_t cb_cleanup(void *b_) 321{ 322 apr_pollcb_t *pollcb = (apr_pollcb_t *) b_; 323 close(pollcb->fd); 324 return APR_SUCCESS; 325} 326 327static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, 328 apr_uint32_t size, 329 apr_pool_t *p, 330 apr_uint32_t flags) 331{ 332 int fd; 333 334 fd = kqueue(); 335 if (fd < 0) { 336 return apr_get_netos_error(); 337 } 338 339 { 340 int flags; 341 342 if ((flags = fcntl(fd, F_GETFD)) == -1) 343 return errno; 344 345 flags |= FD_CLOEXEC; 346 if (fcntl(fd, F_SETFD, flags) == -1) 347 return errno; 348 } 349 350 pollcb->fd = fd; 351 pollcb->pollset.ke = (struct kevent *)apr_pcalloc(p, 2 * size * sizeof(struct kevent)); 352 apr_pool_cleanup_register(p, pollcb, cb_cleanup, apr_pool_cleanup_null); 353 354 return APR_SUCCESS; 355} 356 357static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, 358 apr_pollfd_t *descriptor) 359{ 360 apr_os_sock_t fd; 361 struct kevent ev; 362 apr_status_t rv = APR_SUCCESS; 363 364 if (descriptor->desc_type == APR_POLL_SOCKET) { 365 fd = descriptor->desc.s->socketdes; 366 } 367 else { 368 fd = descriptor->desc.f->filedes; 369 } 370 371 if (descriptor->reqevents & APR_POLLIN) { 372 EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, descriptor); 373 374 if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) == -1) { 375 rv = apr_get_netos_error(); 376 } 377 } 378 379 if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) { 380 EV_SET(&ev, fd, EVFILT_WRITE, EV_ADD, 0, 0, descriptor); 381 382 if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) == -1) { 383 rv = apr_get_netos_error(); 384 } 385 } 386 387 return rv; 388} 389 390static apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb, 391 apr_pollfd_t *descriptor) 392{ 393 apr_status_t rv; 394 struct kevent ev; 395 apr_os_sock_t fd; 396 397 if (descriptor->desc_type == APR_POLL_SOCKET) { 398 fd = descriptor->desc.s->socketdes; 399 } 400 else { 401 fd = descriptor->desc.f->filedes; 402 } 403 404 rv = APR_NOTFOUND; /* unless at least one of the specified conditions is */ 405 if (descriptor->reqevents & APR_POLLIN) { 406 EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); 407 408 if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) != -1) { 409 rv = APR_SUCCESS; 410 } 411 } 412 413 if (descriptor->reqevents & APR_POLLOUT) { 414 EV_SET(&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 415 416 if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) != -1) { 417 rv = APR_SUCCESS; 418 } 419 } 420 421 return rv; 422} 423 424 425static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, 426 apr_interval_time_t timeout, 427 apr_pollcb_cb_t func, 428 void *baton) 429{ 430 int ret, i; 431 struct timespec tv, *tvptr; 432 apr_status_t rv = APR_SUCCESS; 433 434 if (timeout < 0) { 435 tvptr = NULL; 436 } 437 else { 438 tv.tv_sec = (long) apr_time_sec(timeout); 439 tv.tv_nsec = (long) apr_time_usec(timeout) * 1000; 440 tvptr = &tv; 441 } 442 443 ret = kevent(pollcb->fd, NULL, 0, pollcb->pollset.ke, 2 * pollcb->nalloc, 444 tvptr); 445 446 if (ret < 0) { 447 rv = apr_get_netos_error(); 448 } 449 else if (ret == 0) { 450 rv = APR_TIMEUP; 451 } 452 else { 453 for (i = 0; i < ret; i++) { 454 apr_pollfd_t *pollfd = (apr_pollfd_t *)(pollcb->pollset.ke[i].udata); 455 456 pollfd->rtnevents = get_kqueue_revent(pollcb->pollset.ke[i].filter, 457 pollcb->pollset.ke[i].flags); 458 459 rv = func(baton, pollfd); 460 461 if (rv) { 462 return rv; 463 } 464 } 465 } 466 467 return rv; 468} 469 470static apr_pollcb_provider_t impl_cb = { 471 impl_pollcb_create, 472 impl_pollcb_add, 473 impl_pollcb_remove, 474 impl_pollcb_poll, 475 "kqueue" 476}; 477 478apr_pollcb_provider_t *apr_pollcb_provider_kqueue = &impl_cb; 479 480#endif /* HAVE_KQUEUE */ 481