pollset.c revision 269847
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#ifdef WIN32 18/* POSIX defines 1024 for the FD_SETSIZE */ 19#define FD_SETSIZE 1024 20#endif 21 22#include "apr.h" 23#include "apr_poll.h" 24#include "apr_time.h" 25#include "apr_portable.h" 26#include "apr_arch_file_io.h" 27#include "apr_arch_networkio.h" 28#include "apr_arch_poll_private.h" 29#include "apr_arch_inherit.h" 30 31static apr_pollset_method_e pollset_default_method = POLLSET_DEFAULT_METHOD; 32 33#if !APR_FILES_AS_SOCKETS 34#if defined (WIN32) 35 36/* Create a dummy wakeup socket pipe for interrupting the poller 37 */ 38static apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) 39{ 40 apr_status_t rv; 41 42 if ((rv = apr_file_socket_pipe_create(&pollset->wakeup_pipe[0], 43 &pollset->wakeup_pipe[1], 44 pollset->pool)) != APR_SUCCESS) 45 return rv; 46 47 pollset->wakeup_pfd.p = pollset->pool; 48 pollset->wakeup_pfd.reqevents = APR_POLLIN; 49 pollset->wakeup_pfd.desc_type = APR_POLL_FILE; 50 pollset->wakeup_pfd.desc.f = pollset->wakeup_pipe[0]; 51 52 return apr_pollset_add(pollset, &pollset->wakeup_pfd); 53} 54 55#else /* !WIN32 */ 56static apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) 57{ 58 return APR_ENOTIMPL; 59} 60 61static apr_status_t apr_file_socket_pipe_close(apr_file_t *file) 62{ 63 return APR_ENOTIMPL; 64} 65 66#endif /* WIN32 */ 67#else /* APR_FILES_AS_SOCKETS */ 68 69/* Create a dummy wakeup pipe for interrupting the poller 70 */ 71static apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) 72{ 73 apr_status_t rv; 74 75 if ((rv = apr_file_pipe_create(&pollset->wakeup_pipe[0], 76 &pollset->wakeup_pipe[1], 77 pollset->pool)) != APR_SUCCESS) 78 return rv; 79 80 pollset->wakeup_pfd.p = pollset->pool; 81 pollset->wakeup_pfd.reqevents = APR_POLLIN; 82 pollset->wakeup_pfd.desc_type = APR_POLL_FILE; 83 pollset->wakeup_pfd.desc.f = pollset->wakeup_pipe[0]; 84 85 { 86 int flags; 87 88 if ((flags = fcntl(pollset->wakeup_pipe[0]->filedes, F_GETFD)) == -1) 89 return errno; 90 91 flags |= FD_CLOEXEC; 92 if (fcntl(pollset->wakeup_pipe[0]->filedes, F_SETFD, flags) == -1) 93 return errno; 94 } 95 { 96 int flags; 97 98 if ((flags = fcntl(pollset->wakeup_pipe[1]->filedes, F_GETFD)) == -1) 99 return errno; 100 101 flags |= FD_CLOEXEC; 102 if (fcntl(pollset->wakeup_pipe[1]->filedes, F_SETFD, flags) == -1) 103 return errno; 104 } 105 106 return apr_pollset_add(pollset, &pollset->wakeup_pfd); 107} 108#endif /* !APR_FILES_AS_SOCKETS */ 109 110/* Read and discard what's ever in the wakeup pipe. 111 */ 112void apr_pollset_drain_wakeup_pipe(apr_pollset_t *pollset) 113{ 114 char rb[512]; 115 apr_size_t nr = sizeof(rb); 116 117 while (apr_file_read(pollset->wakeup_pipe[0], rb, &nr) == APR_SUCCESS) { 118 /* Although we write just one byte to the other end of the pipe 119 * during wakeup, multiple threads could call the wakeup. 120 * So simply drain out from the input side of the pipe all 121 * the data. 122 */ 123 if (nr != sizeof(rb)) 124 break; 125 } 126} 127 128static apr_status_t pollset_cleanup(void *p) 129{ 130 apr_pollset_t *pollset = (apr_pollset_t *) p; 131 if (pollset->provider->cleanup) { 132 (*pollset->provider->cleanup)(pollset); 133 } 134 if (pollset->flags & APR_POLLSET_WAKEABLE) { 135 /* Close both sides of the wakeup pipe */ 136 if (pollset->wakeup_pipe[0]) { 137#if APR_FILES_AS_SOCKETS 138 apr_file_close(pollset->wakeup_pipe[0]); 139#else 140 apr_file_socket_pipe_close(pollset->wakeup_pipe[0]); 141#endif 142 pollset->wakeup_pipe[0] = NULL; 143 } 144 if (pollset->wakeup_pipe[1]) { 145#if APR_FILES_AS_SOCKETS 146 apr_file_close(pollset->wakeup_pipe[1]); 147#else 148 apr_file_socket_pipe_close(pollset->wakeup_pipe[1]); 149#endif 150 pollset->wakeup_pipe[1] = NULL; 151 } 152 } 153 154 return APR_SUCCESS; 155} 156 157#if defined(HAVE_KQUEUE) 158extern apr_pollset_provider_t *apr_pollset_provider_kqueue; 159#endif 160#if defined(HAVE_PORT_CREATE) 161extern apr_pollset_provider_t *apr_pollset_provider_port; 162#endif 163#if defined(HAVE_EPOLL) 164extern apr_pollset_provider_t *apr_pollset_provider_epoll; 165#endif 166#if defined(HAVE_AIO_MSGQ) 167extern apr_pollset_provider_t *apr_pollset_provider_aio_msgq; 168#endif 169#if defined(HAVE_POLL) 170extern apr_pollset_provider_t *apr_pollset_provider_poll; 171#endif 172extern apr_pollset_provider_t *apr_pollset_provider_select; 173 174static apr_pollset_provider_t *pollset_provider(apr_pollset_method_e method) 175{ 176 apr_pollset_provider_t *provider = NULL; 177 switch (method) { 178 case APR_POLLSET_KQUEUE: 179#if defined(HAVE_KQUEUE) 180 provider = apr_pollset_provider_kqueue; 181#endif 182 break; 183 case APR_POLLSET_PORT: 184#if defined(HAVE_PORT_CREATE) 185 provider = apr_pollset_provider_port; 186#endif 187 break; 188 case APR_POLLSET_EPOLL: 189#if defined(HAVE_EPOLL) 190 provider = apr_pollset_provider_epoll; 191#endif 192 break; 193 case APR_POLLSET_AIO_MSGQ: 194#if defined(HAVE_AIO_MSGQ) 195 provider = apr_pollset_provider_aio_msgq; 196#endif 197 break; 198 case APR_POLLSET_POLL: 199#if defined(HAVE_POLL) 200 provider = apr_pollset_provider_poll; 201#endif 202 break; 203 case APR_POLLSET_SELECT: 204 provider = apr_pollset_provider_select; 205 break; 206 case APR_POLLSET_DEFAULT: 207 break; 208 } 209 return provider; 210} 211 212APR_DECLARE(apr_status_t) apr_pollset_create_ex(apr_pollset_t **ret_pollset, 213 apr_uint32_t size, 214 apr_pool_t *p, 215 apr_uint32_t flags, 216 apr_pollset_method_e method) 217{ 218 apr_status_t rv; 219 apr_pollset_t *pollset; 220 apr_pollset_provider_t *provider = NULL; 221 222 *ret_pollset = NULL; 223 224 #ifdef WIN32 225 /* Favor WSAPoll if supported. 226 * This will work only if ws2_32.dll has WSAPoll funtion. 227 * In other cases it will fall back to select() method unless 228 * the APR_POLLSET_NODEFAULT is added to the flags. 229 */ 230 if (method == APR_POLLSET_DEFAULT) { 231 method = APR_POLLSET_POLL; 232 } 233 #endif 234 235 if (method == APR_POLLSET_DEFAULT) 236 method = pollset_default_method; 237 while (provider == NULL) { 238 provider = pollset_provider(method); 239 if (!provider) { 240 if ((flags & APR_POLLSET_NODEFAULT) == APR_POLLSET_NODEFAULT) 241 return APR_ENOTIMPL; 242 if (method == pollset_default_method) 243 return APR_ENOTIMPL; 244 method = pollset_default_method; 245 } 246 } 247 if (flags & APR_POLLSET_WAKEABLE) { 248 /* Add room for wakeup descriptor */ 249 size++; 250 } 251 252 pollset = apr_palloc(p, sizeof(*pollset)); 253 pollset->nelts = 0; 254 pollset->nalloc = size; 255 pollset->pool = p; 256 pollset->flags = flags; 257 pollset->provider = provider; 258 259 rv = (*provider->create)(pollset, size, p, flags); 260 if (rv == APR_ENOTIMPL) { 261 if (method == pollset_default_method) { 262 return rv; 263 } 264 provider = pollset_provider(pollset_default_method); 265 if (!provider) { 266 return APR_ENOTIMPL; 267 } 268 rv = (*provider->create)(pollset, size, p, flags); 269 if (rv != APR_SUCCESS) { 270 return rv; 271 } 272 pollset->provider = provider; 273 } 274 else if (rv != APR_SUCCESS) { 275 return rv; 276 } 277 if (flags & APR_POLLSET_WAKEABLE) { 278 /* Create wakeup pipe */ 279 if ((rv = create_wakeup_pipe(pollset)) != APR_SUCCESS) { 280 return rv; 281 } 282 } 283 if ((flags & APR_POLLSET_WAKEABLE) || provider->cleanup) 284 apr_pool_cleanup_register(p, pollset, pollset_cleanup, 285 apr_pool_cleanup_null); 286 287 *ret_pollset = pollset; 288 return APR_SUCCESS; 289} 290 291APR_DECLARE(const char *) apr_pollset_method_name(apr_pollset_t *pollset) 292{ 293 return pollset->provider->name; 294} 295 296APR_DECLARE(const char *) apr_poll_method_defname() 297{ 298 apr_pollset_provider_t *provider = NULL; 299 300 provider = pollset_provider(pollset_default_method); 301 if (provider) 302 return provider->name; 303 else 304 return "unknown"; 305} 306 307APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset, 308 apr_uint32_t size, 309 apr_pool_t *p, 310 apr_uint32_t flags) 311{ 312 apr_pollset_method_e method = APR_POLLSET_DEFAULT; 313 return apr_pollset_create_ex(pollset, size, p, flags, method); 314} 315 316APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t * pollset) 317{ 318 if (pollset->flags & APR_POLLSET_WAKEABLE || 319 pollset->provider->cleanup) 320 return apr_pool_cleanup_run(pollset->pool, pollset, 321 pollset_cleanup); 322 else 323 return APR_SUCCESS; 324} 325 326APR_DECLARE(apr_status_t) apr_pollset_wakeup(apr_pollset_t *pollset) 327{ 328 if (pollset->flags & APR_POLLSET_WAKEABLE) 329 return apr_file_putc(1, pollset->wakeup_pipe[1]); 330 else 331 return APR_EINIT; 332} 333 334APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, 335 const apr_pollfd_t *descriptor) 336{ 337 return (*pollset->provider->add)(pollset, descriptor); 338} 339 340APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, 341 const apr_pollfd_t *descriptor) 342{ 343 return (*pollset->provider->remove)(pollset, descriptor); 344} 345 346APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset, 347 apr_interval_time_t timeout, 348 apr_int32_t *num, 349 const apr_pollfd_t **descriptors) 350{ 351 return (*pollset->provider->poll)(pollset, timeout, num, descriptors); 352} 353