1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter 17251875Speter#ifdef WIN32 18251875Speter/* POSIX defines 1024 for the FD_SETSIZE */ 19251875Speter#define FD_SETSIZE 1024 20251875Speter#endif 21251875Speter 22251875Speter#include "apr.h" 23251875Speter#include "apr_poll.h" 24251875Speter#include "apr_time.h" 25251875Speter#include "apr_portable.h" 26251875Speter#include "apr_arch_file_io.h" 27251875Speter#include "apr_arch_networkio.h" 28251875Speter#include "apr_arch_poll_private.h" 29251875Speter#include "apr_arch_inherit.h" 30251875Speter 31251875Speterstatic apr_pollset_method_e pollset_default_method = POLLSET_DEFAULT_METHOD; 32251875Speter 33251875Speter#if !APR_FILES_AS_SOCKETS 34251875Speter#if defined (WIN32) 35251875Speter 36251875Speter/* Create a dummy wakeup socket pipe for interrupting the poller 37251875Speter */ 38251875Speterstatic apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) 39251875Speter{ 40251875Speter apr_status_t rv; 41251875Speter 42251875Speter if ((rv = apr_file_socket_pipe_create(&pollset->wakeup_pipe[0], 43251875Speter &pollset->wakeup_pipe[1], 44251875Speter pollset->pool)) != APR_SUCCESS) 45251875Speter return rv; 46251875Speter 47251875Speter pollset->wakeup_pfd.p = pollset->pool; 48251875Speter pollset->wakeup_pfd.reqevents = APR_POLLIN; 49251875Speter pollset->wakeup_pfd.desc_type = APR_POLL_FILE; 50251875Speter pollset->wakeup_pfd.desc.f = pollset->wakeup_pipe[0]; 51251875Speter 52251875Speter return apr_pollset_add(pollset, &pollset->wakeup_pfd); 53251875Speter} 54251875Speter 55251875Speter#else /* !WIN32 */ 56251875Speterstatic apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) 57251875Speter{ 58251875Speter return APR_ENOTIMPL; 59251875Speter} 60251875Speter 61251875Speterstatic apr_status_t apr_file_socket_pipe_close(apr_file_t *file) 62251875Speter{ 63251875Speter return APR_ENOTIMPL; 64251875Speter} 65251875Speter 66251875Speter#endif /* WIN32 */ 67251875Speter#else /* APR_FILES_AS_SOCKETS */ 68251875Speter 69251875Speter/* Create a dummy wakeup pipe for interrupting the poller 70251875Speter */ 71251875Speterstatic apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) 72251875Speter{ 73251875Speter apr_status_t rv; 74251875Speter 75251875Speter if ((rv = apr_file_pipe_create(&pollset->wakeup_pipe[0], 76251875Speter &pollset->wakeup_pipe[1], 77251875Speter pollset->pool)) != APR_SUCCESS) 78251875Speter return rv; 79251875Speter 80251875Speter pollset->wakeup_pfd.p = pollset->pool; 81251875Speter pollset->wakeup_pfd.reqevents = APR_POLLIN; 82251875Speter pollset->wakeup_pfd.desc_type = APR_POLL_FILE; 83251875Speter pollset->wakeup_pfd.desc.f = pollset->wakeup_pipe[0]; 84251875Speter 85251875Speter { 86251875Speter int flags; 87251875Speter 88251875Speter if ((flags = fcntl(pollset->wakeup_pipe[0]->filedes, F_GETFD)) == -1) 89251875Speter return errno; 90251875Speter 91251875Speter flags |= FD_CLOEXEC; 92251875Speter if (fcntl(pollset->wakeup_pipe[0]->filedes, F_SETFD, flags) == -1) 93251875Speter return errno; 94251875Speter } 95251875Speter { 96251875Speter int flags; 97251875Speter 98251875Speter if ((flags = fcntl(pollset->wakeup_pipe[1]->filedes, F_GETFD)) == -1) 99251875Speter return errno; 100251875Speter 101251875Speter flags |= FD_CLOEXEC; 102251875Speter if (fcntl(pollset->wakeup_pipe[1]->filedes, F_SETFD, flags) == -1) 103251875Speter return errno; 104251875Speter } 105251875Speter 106251875Speter return apr_pollset_add(pollset, &pollset->wakeup_pfd); 107251875Speter} 108251875Speter#endif /* !APR_FILES_AS_SOCKETS */ 109251875Speter 110251875Speter/* Read and discard what's ever in the wakeup pipe. 111251875Speter */ 112251875Spetervoid apr_pollset_drain_wakeup_pipe(apr_pollset_t *pollset) 113251875Speter{ 114251875Speter char rb[512]; 115251875Speter apr_size_t nr = sizeof(rb); 116251875Speter 117251875Speter while (apr_file_read(pollset->wakeup_pipe[0], rb, &nr) == APR_SUCCESS) { 118251875Speter /* Although we write just one byte to the other end of the pipe 119251875Speter * during wakeup, multiple threads could call the wakeup. 120251875Speter * So simply drain out from the input side of the pipe all 121251875Speter * the data. 122251875Speter */ 123251875Speter if (nr != sizeof(rb)) 124251875Speter break; 125251875Speter } 126251875Speter} 127251875Speter 128251875Speterstatic apr_status_t pollset_cleanup(void *p) 129251875Speter{ 130251875Speter apr_pollset_t *pollset = (apr_pollset_t *) p; 131251875Speter if (pollset->provider->cleanup) { 132251875Speter (*pollset->provider->cleanup)(pollset); 133251875Speter } 134251875Speter if (pollset->flags & APR_POLLSET_WAKEABLE) { 135251875Speter /* Close both sides of the wakeup pipe */ 136251875Speter if (pollset->wakeup_pipe[0]) { 137251875Speter#if APR_FILES_AS_SOCKETS 138251875Speter apr_file_close(pollset->wakeup_pipe[0]); 139251875Speter#else 140251875Speter apr_file_socket_pipe_close(pollset->wakeup_pipe[0]); 141251875Speter#endif 142251875Speter pollset->wakeup_pipe[0] = NULL; 143251875Speter } 144251875Speter if (pollset->wakeup_pipe[1]) { 145251875Speter#if APR_FILES_AS_SOCKETS 146251875Speter apr_file_close(pollset->wakeup_pipe[1]); 147251875Speter#else 148251875Speter apr_file_socket_pipe_close(pollset->wakeup_pipe[1]); 149251875Speter#endif 150251875Speter pollset->wakeup_pipe[1] = NULL; 151251875Speter } 152251875Speter } 153251875Speter 154251875Speter return APR_SUCCESS; 155251875Speter} 156251875Speter 157251875Speter#if defined(HAVE_KQUEUE) 158251875Speterextern apr_pollset_provider_t *apr_pollset_provider_kqueue; 159251875Speter#endif 160251875Speter#if defined(HAVE_PORT_CREATE) 161251875Speterextern apr_pollset_provider_t *apr_pollset_provider_port; 162251875Speter#endif 163251875Speter#if defined(HAVE_EPOLL) 164251875Speterextern apr_pollset_provider_t *apr_pollset_provider_epoll; 165251875Speter#endif 166269847Speter#if defined(HAVE_AIO_MSGQ) 167269847Speterextern apr_pollset_provider_t *apr_pollset_provider_aio_msgq; 168269847Speter#endif 169251875Speter#if defined(HAVE_POLL) 170251875Speterextern apr_pollset_provider_t *apr_pollset_provider_poll; 171251875Speter#endif 172251875Speterextern apr_pollset_provider_t *apr_pollset_provider_select; 173251875Speter 174251875Speterstatic apr_pollset_provider_t *pollset_provider(apr_pollset_method_e method) 175251875Speter{ 176251875Speter apr_pollset_provider_t *provider = NULL; 177251875Speter switch (method) { 178251875Speter case APR_POLLSET_KQUEUE: 179251875Speter#if defined(HAVE_KQUEUE) 180251875Speter provider = apr_pollset_provider_kqueue; 181251875Speter#endif 182251875Speter break; 183251875Speter case APR_POLLSET_PORT: 184251875Speter#if defined(HAVE_PORT_CREATE) 185251875Speter provider = apr_pollset_provider_port; 186251875Speter#endif 187251875Speter break; 188251875Speter case APR_POLLSET_EPOLL: 189251875Speter#if defined(HAVE_EPOLL) 190251875Speter provider = apr_pollset_provider_epoll; 191251875Speter#endif 192251875Speter break; 193269847Speter case APR_POLLSET_AIO_MSGQ: 194269847Speter#if defined(HAVE_AIO_MSGQ) 195269847Speter provider = apr_pollset_provider_aio_msgq; 196269847Speter#endif 197269847Speter break; 198251875Speter case APR_POLLSET_POLL: 199251875Speter#if defined(HAVE_POLL) 200251875Speter provider = apr_pollset_provider_poll; 201251875Speter#endif 202251875Speter break; 203251875Speter case APR_POLLSET_SELECT: 204251875Speter provider = apr_pollset_provider_select; 205251875Speter break; 206251875Speter case APR_POLLSET_DEFAULT: 207251875Speter break; 208251875Speter } 209251875Speter return provider; 210251875Speter} 211251875Speter 212251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_create_ex(apr_pollset_t **ret_pollset, 213251875Speter apr_uint32_t size, 214251875Speter apr_pool_t *p, 215251875Speter apr_uint32_t flags, 216251875Speter apr_pollset_method_e method) 217251875Speter{ 218251875Speter apr_status_t rv; 219251875Speter apr_pollset_t *pollset; 220251875Speter apr_pollset_provider_t *provider = NULL; 221251875Speter 222251875Speter *ret_pollset = NULL; 223251875Speter 224251875Speter #ifdef WIN32 225251875Speter /* Favor WSAPoll if supported. 226251875Speter * This will work only if ws2_32.dll has WSAPoll funtion. 227251875Speter * In other cases it will fall back to select() method unless 228251875Speter * the APR_POLLSET_NODEFAULT is added to the flags. 229251875Speter */ 230251875Speter if (method == APR_POLLSET_DEFAULT) { 231251875Speter method = APR_POLLSET_POLL; 232251875Speter } 233251875Speter #endif 234251875Speter 235251875Speter if (method == APR_POLLSET_DEFAULT) 236251875Speter method = pollset_default_method; 237251875Speter while (provider == NULL) { 238251875Speter provider = pollset_provider(method); 239251875Speter if (!provider) { 240251875Speter if ((flags & APR_POLLSET_NODEFAULT) == APR_POLLSET_NODEFAULT) 241251875Speter return APR_ENOTIMPL; 242251875Speter if (method == pollset_default_method) 243251875Speter return APR_ENOTIMPL; 244251875Speter method = pollset_default_method; 245251875Speter } 246251875Speter } 247251875Speter if (flags & APR_POLLSET_WAKEABLE) { 248251875Speter /* Add room for wakeup descriptor */ 249251875Speter size++; 250251875Speter } 251251875Speter 252251875Speter pollset = apr_palloc(p, sizeof(*pollset)); 253251875Speter pollset->nelts = 0; 254251875Speter pollset->nalloc = size; 255251875Speter pollset->pool = p; 256251875Speter pollset->flags = flags; 257251875Speter pollset->provider = provider; 258251875Speter 259251875Speter rv = (*provider->create)(pollset, size, p, flags); 260251875Speter if (rv == APR_ENOTIMPL) { 261251875Speter if (method == pollset_default_method) { 262251875Speter return rv; 263251875Speter } 264251875Speter provider = pollset_provider(pollset_default_method); 265251875Speter if (!provider) { 266251875Speter return APR_ENOTIMPL; 267251875Speter } 268251875Speter rv = (*provider->create)(pollset, size, p, flags); 269251875Speter if (rv != APR_SUCCESS) { 270251875Speter return rv; 271251875Speter } 272251875Speter pollset->provider = provider; 273251875Speter } 274251875Speter else if (rv != APR_SUCCESS) { 275251875Speter return rv; 276251875Speter } 277251875Speter if (flags & APR_POLLSET_WAKEABLE) { 278251875Speter /* Create wakeup pipe */ 279251875Speter if ((rv = create_wakeup_pipe(pollset)) != APR_SUCCESS) { 280251875Speter return rv; 281251875Speter } 282251875Speter } 283251875Speter if ((flags & APR_POLLSET_WAKEABLE) || provider->cleanup) 284251875Speter apr_pool_cleanup_register(p, pollset, pollset_cleanup, 285251875Speter apr_pool_cleanup_null); 286251875Speter 287251875Speter *ret_pollset = pollset; 288251875Speter return APR_SUCCESS; 289251875Speter} 290251875Speter 291251875SpeterAPR_DECLARE(const char *) apr_pollset_method_name(apr_pollset_t *pollset) 292251875Speter{ 293251875Speter return pollset->provider->name; 294251875Speter} 295251875Speter 296251875SpeterAPR_DECLARE(const char *) apr_poll_method_defname() 297251875Speter{ 298251875Speter apr_pollset_provider_t *provider = NULL; 299251875Speter 300251875Speter provider = pollset_provider(pollset_default_method); 301251875Speter if (provider) 302251875Speter return provider->name; 303251875Speter else 304251875Speter return "unknown"; 305251875Speter} 306251875Speter 307251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset, 308251875Speter apr_uint32_t size, 309251875Speter apr_pool_t *p, 310251875Speter apr_uint32_t flags) 311251875Speter{ 312251875Speter apr_pollset_method_e method = APR_POLLSET_DEFAULT; 313251875Speter return apr_pollset_create_ex(pollset, size, p, flags, method); 314251875Speter} 315251875Speter 316251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t * pollset) 317251875Speter{ 318251875Speter if (pollset->flags & APR_POLLSET_WAKEABLE || 319251875Speter pollset->provider->cleanup) 320251875Speter return apr_pool_cleanup_run(pollset->pool, pollset, 321251875Speter pollset_cleanup); 322251875Speter else 323251875Speter return APR_SUCCESS; 324251875Speter} 325251875Speter 326251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_wakeup(apr_pollset_t *pollset) 327251875Speter{ 328251875Speter if (pollset->flags & APR_POLLSET_WAKEABLE) 329251875Speter return apr_file_putc(1, pollset->wakeup_pipe[1]); 330251875Speter else 331251875Speter return APR_EINIT; 332251875Speter} 333251875Speter 334251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, 335251875Speter const apr_pollfd_t *descriptor) 336251875Speter{ 337251875Speter return (*pollset->provider->add)(pollset, descriptor); 338251875Speter} 339251875Speter 340251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, 341251875Speter const apr_pollfd_t *descriptor) 342251875Speter{ 343251875Speter return (*pollset->provider->remove)(pollset, descriptor); 344251875Speter} 345251875Speter 346251875SpeterAPR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset, 347251875Speter apr_interval_time_t timeout, 348251875Speter apr_int32_t *num, 349251875Speter const apr_pollfd_t **descriptors) 350251875Speter{ 351251875Speter return (*pollset->provider->poll)(pollset, timeout, num, descriptors); 352251875Speter} 353