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_POLL) 167extern apr_pollset_provider_t *apr_pollset_provider_poll; 168#endif 169extern apr_pollset_provider_t *apr_pollset_provider_select; 170 171static apr_pollset_provider_t *pollset_provider(apr_pollset_method_e method) 172{ 173 apr_pollset_provider_t *provider = NULL; 174 switch (method) { 175 case APR_POLLSET_KQUEUE: 176#if defined(HAVE_KQUEUE) 177 provider = apr_pollset_provider_kqueue; 178#endif 179 break; 180 case APR_POLLSET_PORT: 181#if defined(HAVE_PORT_CREATE) 182 provider = apr_pollset_provider_port; 183#endif 184 break; 185 case APR_POLLSET_EPOLL: 186#if defined(HAVE_EPOLL) 187 provider = apr_pollset_provider_epoll; 188#endif 189 break; 190 case APR_POLLSET_POLL: 191#if defined(HAVE_POLL) 192 provider = apr_pollset_provider_poll; 193#endif 194 break; 195 case APR_POLLSET_SELECT: 196 provider = apr_pollset_provider_select; 197 break; 198 case APR_POLLSET_DEFAULT: 199 break; 200 } 201 return provider; 202} 203 204APR_DECLARE(apr_status_t) apr_pollset_create_ex(apr_pollset_t **ret_pollset, 205 apr_uint32_t size, 206 apr_pool_t *p, 207 apr_uint32_t flags, 208 apr_pollset_method_e method) 209{ 210 apr_status_t rv; 211 apr_pollset_t *pollset; 212 apr_pollset_provider_t *provider = NULL; 213 214 *ret_pollset = NULL; 215 216 #ifdef WIN32 217 /* Favor WSAPoll if supported. 218 * This will work only if ws2_32.dll has WSAPoll funtion. 219 * In other cases it will fall back to select() method unless 220 * the APR_POLLSET_NODEFAULT is added to the flags. 221 */ 222 if (method == APR_POLLSET_DEFAULT) { 223 method = APR_POLLSET_POLL; 224 } 225 #endif 226 227 if (method == APR_POLLSET_DEFAULT) 228 method = pollset_default_method; 229 while (provider == NULL) { 230 provider = pollset_provider(method); 231 if (!provider) { 232 if ((flags & APR_POLLSET_NODEFAULT) == APR_POLLSET_NODEFAULT) 233 return APR_ENOTIMPL; 234 if (method == pollset_default_method) 235 return APR_ENOTIMPL; 236 method = pollset_default_method; 237 } 238 } 239 if (flags & APR_POLLSET_WAKEABLE) { 240 /* Add room for wakeup descriptor */ 241 size++; 242 } 243 244 pollset = apr_palloc(p, sizeof(*pollset)); 245 pollset->nelts = 0; 246 pollset->nalloc = size; 247 pollset->pool = p; 248 pollset->flags = flags; 249 pollset->provider = provider; 250 251 rv = (*provider->create)(pollset, size, p, flags); 252 if (rv == APR_ENOTIMPL) { 253 if (method == pollset_default_method) { 254 return rv; 255 } 256 provider = pollset_provider(pollset_default_method); 257 if (!provider) { 258 return APR_ENOTIMPL; 259 } 260 rv = (*provider->create)(pollset, size, p, flags); 261 if (rv != APR_SUCCESS) { 262 return rv; 263 } 264 pollset->provider = provider; 265 } 266 else if (rv != APR_SUCCESS) { 267 return rv; 268 } 269 if (flags & APR_POLLSET_WAKEABLE) { 270 /* Create wakeup pipe */ 271 if ((rv = create_wakeup_pipe(pollset)) != APR_SUCCESS) { 272 return rv; 273 } 274 } 275 if ((flags & APR_POLLSET_WAKEABLE) || provider->cleanup) 276 apr_pool_cleanup_register(p, pollset, pollset_cleanup, 277 apr_pool_cleanup_null); 278 279 *ret_pollset = pollset; 280 return APR_SUCCESS; 281} 282 283APR_DECLARE(const char *) apr_pollset_method_name(apr_pollset_t *pollset) 284{ 285 return pollset->provider->name; 286} 287 288APR_DECLARE(const char *) apr_poll_method_defname() 289{ 290 apr_pollset_provider_t *provider = NULL; 291 292 provider = pollset_provider(pollset_default_method); 293 if (provider) 294 return provider->name; 295 else 296 return "unknown"; 297} 298 299APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset, 300 apr_uint32_t size, 301 apr_pool_t *p, 302 apr_uint32_t flags) 303{ 304 apr_pollset_method_e method = APR_POLLSET_DEFAULT; 305 return apr_pollset_create_ex(pollset, size, p, flags, method); 306} 307 308APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t * pollset) 309{ 310 if (pollset->flags & APR_POLLSET_WAKEABLE || 311 pollset->provider->cleanup) 312 return apr_pool_cleanup_run(pollset->pool, pollset, 313 pollset_cleanup); 314 else 315 return APR_SUCCESS; 316} 317 318APR_DECLARE(apr_status_t) apr_pollset_wakeup(apr_pollset_t *pollset) 319{ 320 if (pollset->flags & APR_POLLSET_WAKEABLE) 321 return apr_file_putc(1, pollset->wakeup_pipe[1]); 322 else 323 return APR_EINIT; 324} 325 326APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, 327 const apr_pollfd_t *descriptor) 328{ 329 return (*pollset->provider->add)(pollset, descriptor); 330} 331 332APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, 333 const apr_pollfd_t *descriptor) 334{ 335 return (*pollset->provider->remove)(pollset, descriptor); 336} 337 338APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset, 339 apr_interval_time_t timeout, 340 apr_int32_t *num, 341 const apr_pollfd_t **descriptors) 342{ 343 return (*pollset->provider->poll)(pollset, timeout, num, descriptors); 344} 345