poll.c revision 289166
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_misc.h" 24#include "apr_arch_poll_private.h" 25 26#if defined(HAVE_POLL) 27 28#ifdef HAVE_ALLOCA_H 29#include <alloca.h> 30#endif 31 32static apr_int16_t get_event(apr_int16_t event) 33{ 34 apr_int16_t rv = 0; 35 36 if (event & APR_POLLIN) 37 rv |= POLLIN; 38 if (event & APR_POLLPRI) 39 rv |= POLLPRI; 40 if (event & APR_POLLOUT) 41 rv |= POLLOUT; 42 /* POLLERR, POLLHUP, and POLLNVAL aren't valid as requested events */ 43 44 return rv; 45} 46 47static apr_int16_t get_revent(apr_int16_t event) 48{ 49 apr_int16_t rv = 0; 50 51 if (event & POLLIN) 52 rv |= APR_POLLIN; 53 if (event & POLLPRI) 54 rv |= APR_POLLPRI; 55 if (event & POLLOUT) 56 rv |= APR_POLLOUT; 57 if (event & POLLERR) 58 rv |= APR_POLLERR; 59 if (event & POLLHUP) 60 rv |= APR_POLLHUP; 61 if (event & POLLNVAL) 62 rv |= APR_POLLNVAL; 63 64 return rv; 65} 66 67#ifdef POLL_USES_POLL 68 69#define SMALL_POLLSET_LIMIT 8 70 71APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t num, 72 apr_int32_t *nsds, 73 apr_interval_time_t timeout) 74{ 75 int i, num_to_poll; 76#ifdef HAVE_VLA 77 /* XXX: I trust that this is a segv when insufficient stack exists? */ 78 struct pollfd pollset[num]; 79#elif defined(HAVE_ALLOCA) 80 struct pollfd *pollset = alloca(sizeof(struct pollfd) * num); 81 if (!pollset) 82 return APR_ENOMEM; 83#else 84 struct pollfd tmp_pollset[SMALL_POLLSET_LIMIT]; 85 struct pollfd *pollset; 86 87 if (num <= SMALL_POLLSET_LIMIT) { 88 pollset = tmp_pollset; 89 } 90 else { 91 /* This does require O(n) to copy the descriptors to the internal 92 * mapping. 93 */ 94 pollset = malloc(sizeof(struct pollfd) * num); 95 /* The other option is adding an apr_pool_abort() fn to invoke 96 * the pool's out of memory handler 97 */ 98 if (!pollset) 99 return APR_ENOMEM; 100 } 101#endif 102 for (i = 0; i < num; i++) { 103 if (aprset[i].desc_type == APR_POLL_SOCKET) { 104 pollset[i].fd = aprset[i].desc.s->socketdes; 105 } 106 else if (aprset[i].desc_type == APR_POLL_FILE) { 107 pollset[i].fd = aprset[i].desc.f->filedes; 108 } 109 else { 110 break; 111 } 112 pollset[i].events = get_event(aprset[i].reqevents); 113 } 114 num_to_poll = i; 115 116 if (timeout > 0) { 117 timeout /= 1000; /* convert microseconds to milliseconds */ 118 } 119 120 i = poll(pollset, num_to_poll, timeout); 121 (*nsds) = i; 122 123 if (i > 0) { /* poll() sets revents only if an event was signalled; 124 * we don't promise to set rtnevents unless an event 125 * was signalled 126 */ 127 for (i = 0; i < num; i++) { 128 aprset[i].rtnevents = get_revent(pollset[i].revents); 129 } 130 } 131 132#if !defined(HAVE_VLA) && !defined(HAVE_ALLOCA) 133 if (num > SMALL_POLLSET_LIMIT) { 134 free(pollset); 135 } 136#endif 137 138 if ((*nsds) < 0) { 139 return apr_get_netos_error(); 140 } 141 if ((*nsds) == 0) { 142 return APR_TIMEUP; 143 } 144 return APR_SUCCESS; 145} 146 147 148#endif /* POLL_USES_POLL */ 149 150struct apr_pollset_private_t 151{ 152 struct pollfd *pollset; 153 apr_pollfd_t *query_set; 154 apr_pollfd_t *result_set; 155}; 156 157static apr_status_t impl_pollset_create(apr_pollset_t *pollset, 158 apr_uint32_t size, 159 apr_pool_t *p, 160 apr_uint32_t flags) 161{ 162 if (flags & APR_POLLSET_THREADSAFE) { 163 return APR_ENOTIMPL; 164 } 165#ifdef WIN32 166 if (!APR_HAVE_LATE_DLL_FUNC(WSAPoll)) { 167 return APR_ENOTIMPL; 168 } 169#endif 170 pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); 171 pollset->p->pollset = apr_palloc(p, size * sizeof(struct pollfd)); 172 pollset->p->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); 173 pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); 174 175 return APR_SUCCESS; 176} 177 178static apr_status_t impl_pollset_add(apr_pollset_t *pollset, 179 const apr_pollfd_t *descriptor) 180{ 181 if (pollset->nelts == pollset->nalloc) { 182 return APR_ENOMEM; 183 } 184 185 pollset->p->query_set[pollset->nelts] = *descriptor; 186 187 if (descriptor->desc_type == APR_POLL_SOCKET) { 188 pollset->p->pollset[pollset->nelts].fd = descriptor->desc.s->socketdes; 189 } 190 else { 191#if APR_FILES_AS_SOCKETS 192 pollset->p->pollset[pollset->nelts].fd = descriptor->desc.f->filedes; 193#else 194 if ((pollset->flags & APR_POLLSET_WAKEABLE) && 195 descriptor->desc.f == pollset->wakeup_pipe[0]) 196 pollset->p->pollset[pollset->nelts].fd = (SOCKET)descriptor->desc.f->filedes; 197 else 198 return APR_EBADF; 199#endif 200 } 201 pollset->p->pollset[pollset->nelts].events = 202 get_event(descriptor->reqevents); 203 pollset->nelts++; 204 205 return APR_SUCCESS; 206} 207 208static apr_status_t impl_pollset_remove(apr_pollset_t *pollset, 209 const apr_pollfd_t *descriptor) 210{ 211 apr_uint32_t i; 212 213 for (i = 0; i < pollset->nelts; i++) { 214 if (descriptor->desc.s == pollset->p->query_set[i].desc.s) { 215 /* Found an instance of the fd: remove this and any other copies */ 216 apr_uint32_t dst = i; 217 apr_uint32_t old_nelts = pollset->nelts; 218 pollset->nelts--; 219 for (i++; i < old_nelts; i++) { 220 if (descriptor->desc.s == pollset->p->query_set[i].desc.s) { 221 pollset->nelts--; 222 } 223 else { 224 pollset->p->pollset[dst] = pollset->p->pollset[i]; 225 pollset->p->query_set[dst] = pollset->p->query_set[i]; 226 dst++; 227 } 228 } 229 return APR_SUCCESS; 230 } 231 } 232 233 return APR_NOTFOUND; 234} 235 236static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, 237 apr_interval_time_t timeout, 238 apr_int32_t *num, 239 const apr_pollfd_t **descriptors) 240{ 241 int ret; 242 apr_status_t rv = APR_SUCCESS; 243 244#ifdef WIN32 245 /* WSAPoll() requires at least one socket. */ 246 if (pollset->nelts == 0) { 247 *num = 0; 248 if (timeout > 0) { 249 apr_sleep(timeout); 250 return APR_TIMEUP; 251 } 252 return APR_SUCCESS; 253 } 254 if (timeout > 0) { 255 timeout /= 1000; 256 } 257 ret = WSAPoll(pollset->p->pollset, pollset->nelts, (int)timeout); 258#else 259 if (timeout > 0) { 260 timeout /= 1000; 261 } 262 ret = poll(pollset->p->pollset, pollset->nelts, timeout); 263#endif 264 (*num) = ret; 265 if (ret < 0) { 266 return apr_get_netos_error(); 267 } 268 else if (ret == 0) { 269 return APR_TIMEUP; 270 } 271 else { 272 apr_uint32_t i, j; 273 274 for (i = 0, j = 0; i < pollset->nelts; i++) { 275 if (pollset->p->pollset[i].revents != 0) { 276 /* Check if the polled descriptor is our 277 * wakeup pipe. In that case do not put it result set. 278 */ 279 if ((pollset->flags & APR_POLLSET_WAKEABLE) && 280 pollset->p->query_set[i].desc_type == APR_POLL_FILE && 281 pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) { 282 apr_pollset_drain_wakeup_pipe(pollset); 283 rv = APR_EINTR; 284 } 285 else { 286 pollset->p->result_set[j] = pollset->p->query_set[i]; 287 pollset->p->result_set[j].rtnevents = 288 get_revent(pollset->p->pollset[i].revents); 289 j++; 290 } 291 } 292 } 293 if (((*num) = j) > 0) 294 rv = APR_SUCCESS; 295 } 296 if (descriptors && (*num)) 297 *descriptors = pollset->p->result_set; 298 return rv; 299} 300 301static apr_pollset_provider_t impl = { 302 impl_pollset_create, 303 impl_pollset_add, 304 impl_pollset_remove, 305 impl_pollset_poll, 306 NULL, 307 "poll" 308}; 309 310apr_pollset_provider_t *apr_pollset_provider_poll = &impl; 311 312/* Poll method pollcb. 313 * This is probably usable only for WIN32 having WSAPoll 314 */ 315static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, 316 apr_uint32_t size, 317 apr_pool_t *p, 318 apr_uint32_t flags) 319{ 320#if APR_HAS_THREADS 321 return APR_ENOTIMPL; 322#else 323 pollcb->fd = -1; 324#ifdef WIN32 325 if (!APR_HAVE_LATE_DLL_FUNC(WSAPoll)) { 326 return APR_ENOTIMPL; 327 } 328#endif 329 330 pollcb->pollset.ps = apr_palloc(p, size * sizeof(struct pollfd)); 331 pollcb->copyset = apr_palloc(p, size * sizeof(apr_pollfd_t *)); 332 333 return APR_SUCCESS; 334#endif 335} 336 337static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, 338 apr_pollfd_t *descriptor) 339{ 340 if (pollcb->nelts == pollcb->nalloc) { 341 return APR_ENOMEM; 342 } 343 344 if (descriptor->desc_type == APR_POLL_SOCKET) { 345 pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.s->socketdes; 346 } 347 else { 348#if APR_FILES_AS_SOCKETS 349 pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.f->filedes; 350#else 351 return APR_EBADF; 352#endif 353 } 354 355 pollcb->pollset.ps[pollcb->nelts].events = 356 get_event(descriptor->reqevents); 357 pollcb->copyset[pollcb->nelts] = descriptor; 358 pollcb->nelts++; 359 360 return APR_SUCCESS; 361} 362 363static apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb, 364 apr_pollfd_t *descriptor) 365{ 366 apr_uint32_t i; 367 368 for (i = 0; i < pollcb->nelts; i++) { 369 if (descriptor->desc.s == pollcb->copyset[i]->desc.s) { 370 /* Found an instance of the fd: remove this and any other copies */ 371 apr_uint32_t dst = i; 372 apr_uint32_t old_nelts = pollcb->nelts; 373 pollcb->nelts--; 374 for (i++; i < old_nelts; i++) { 375 if (descriptor->desc.s == pollcb->copyset[i]->desc.s) { 376 pollcb->nelts--; 377 } 378 else { 379 pollcb->pollset.ps[dst] = pollcb->pollset.ps[i]; 380 pollcb->copyset[dst] = pollcb->copyset[i]; 381 dst++; 382 } 383 } 384 return APR_SUCCESS; 385 } 386 } 387 388 return APR_NOTFOUND; 389} 390 391static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, 392 apr_interval_time_t timeout, 393 apr_pollcb_cb_t func, 394 void *baton) 395{ 396 int ret; 397 apr_status_t rv = APR_SUCCESS; 398 apr_uint32_t i; 399 400#ifdef WIN32 401 /* WSAPoll() requires at least one socket. */ 402 if (pollcb->nelts == 0) { 403 if (timeout > 0) { 404 apr_sleep(timeout); 405 return APR_TIMEUP; 406 } 407 return APR_SUCCESS; 408 } 409 if (timeout > 0) { 410 timeout /= 1000; 411 } 412 ret = WSAPoll(pollcb->pollset.ps, pollcb->nelts, (int)timeout); 413#else 414 if (timeout > 0) { 415 timeout /= 1000; 416 } 417 ret = poll(pollcb->pollset.ps, pollcb->nelts, timeout); 418#endif 419 if (ret < 0) { 420 return apr_get_netos_error(); 421 } 422 else if (ret == 0) { 423 return APR_TIMEUP; 424 } 425 else { 426 for (i = 0; i < pollcb->nelts; i++) { 427 if (pollcb->pollset.ps[i].revents != 0) { 428 apr_pollfd_t *pollfd = pollcb->copyset[i]; 429 pollfd->rtnevents = get_revent(pollcb->pollset.ps[i].revents); 430 rv = func(baton, pollfd); 431 if (rv) { 432 return rv; 433 } 434 } 435 } 436 } 437 return rv; 438} 439 440static apr_pollcb_provider_t impl_cb = { 441 impl_pollcb_create, 442 impl_pollcb_add, 443 impl_pollcb_remove, 444 impl_pollcb_poll, 445 "poll" 446}; 447 448apr_pollcb_provider_t *apr_pollcb_provider_poll = &impl_cb; 449 450#endif /* HAVE_POLL */ 451