poll.c revision 251875
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#ifdef WIN32 244 apr_interval_time_t orig_timeout = timeout; 245#endif 246 247 if (timeout > 0) { 248 timeout /= 1000; 249 } 250#ifdef WIN32 251 /* WSAPoll() requires at least one socket. */ 252 if (pollset->nelts == 0) { 253 *num = 0; 254 if (orig_timeout > 0) { 255 apr_sleep(orig_timeout); 256 return APR_TIMEUP; 257 } 258 return APR_SUCCESS; 259 } 260 261 ret = WSAPoll(pollset->p->pollset, pollset->nelts, (int)timeout); 262#else 263 ret = poll(pollset->p->pollset, pollset->nelts, timeout); 264#endif 265 (*num) = ret; 266 if (ret < 0) { 267 return apr_get_netos_error(); 268 } 269 else if (ret == 0) { 270 return APR_TIMEUP; 271 } 272 else { 273 apr_uint32_t i, j; 274 275 for (i = 0, j = 0; i < pollset->nelts; i++) { 276 if (pollset->p->pollset[i].revents != 0) { 277 /* Check if the polled descriptor is our 278 * wakeup pipe. In that case do not put it result set. 279 */ 280 if ((pollset->flags & APR_POLLSET_WAKEABLE) && 281 pollset->p->query_set[i].desc_type == APR_POLL_FILE && 282 pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) { 283 apr_pollset_drain_wakeup_pipe(pollset); 284 rv = APR_EINTR; 285 } 286 else { 287 pollset->p->result_set[j] = pollset->p->query_set[i]; 288 pollset->p->result_set[j].rtnevents = 289 get_revent(pollset->p->pollset[i].revents); 290 j++; 291 } 292 } 293 } 294 if (((*num) = j) > 0) 295 rv = APR_SUCCESS; 296 } 297 if (descriptors && (*num)) 298 *descriptors = pollset->p->result_set; 299 return rv; 300} 301 302static apr_pollset_provider_t impl = { 303 impl_pollset_create, 304 impl_pollset_add, 305 impl_pollset_remove, 306 impl_pollset_poll, 307 NULL, 308 "poll" 309}; 310 311apr_pollset_provider_t *apr_pollset_provider_poll = &impl; 312 313/* Poll method pollcb. 314 * This is probably usable only for WIN32 having WSAPoll 315 */ 316static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, 317 apr_uint32_t size, 318 apr_pool_t *p, 319 apr_uint32_t flags) 320{ 321#if APR_HAS_THREADS 322 return APR_ENOTIMPL; 323#else 324 pollcb->fd = -1; 325#ifdef WIN32 326 if (!APR_HAVE_LATE_DLL_FUNC(WSAPoll)) { 327 return APR_ENOTIMPL; 328 } 329#endif 330 331 pollcb->pollset.ps = apr_palloc(p, size * sizeof(struct pollfd)); 332 pollcb->copyset = apr_palloc(p, size * sizeof(apr_pollfd_t *)); 333 334 return APR_SUCCESS; 335#endif 336} 337 338static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, 339 apr_pollfd_t *descriptor) 340{ 341 if (pollcb->nelts == pollcb->nalloc) { 342 return APR_ENOMEM; 343 } 344 345 if (descriptor->desc_type == APR_POLL_SOCKET) { 346 pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.s->socketdes; 347 } 348 else { 349#if APR_FILES_AS_SOCKETS 350 pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.f->filedes; 351#else 352 return APR_EBADF; 353#endif 354 } 355 356 pollcb->pollset.ps[pollcb->nelts].events = 357 get_event(descriptor->reqevents); 358 pollcb->copyset[pollcb->nelts] = descriptor; 359 pollcb->nelts++; 360 361 return APR_SUCCESS; 362} 363 364static apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb, 365 apr_pollfd_t *descriptor) 366{ 367 apr_uint32_t i; 368 369 for (i = 0; i < pollcb->nelts; i++) { 370 if (descriptor->desc.s == pollcb->copyset[i]->desc.s) { 371 /* Found an instance of the fd: remove this and any other copies */ 372 apr_uint32_t dst = i; 373 apr_uint32_t old_nelts = pollcb->nelts; 374 pollcb->nelts--; 375 for (i++; i < old_nelts; i++) { 376 if (descriptor->desc.s == pollcb->copyset[i]->desc.s) { 377 pollcb->nelts--; 378 } 379 else { 380 pollcb->pollset.ps[dst] = pollcb->pollset.ps[i]; 381 pollcb->copyset[dst] = pollcb->copyset[i]; 382 dst++; 383 } 384 } 385 return APR_SUCCESS; 386 } 387 } 388 389 return APR_NOTFOUND; 390} 391 392static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, 393 apr_interval_time_t timeout, 394 apr_pollcb_cb_t func, 395 void *baton) 396{ 397 int ret; 398 apr_status_t rv = APR_SUCCESS; 399 apr_uint32_t i; 400 401 if (timeout > 0) { 402 timeout /= 1000; 403 } 404#ifdef WIN32 405 ret = WSAPoll(pollcb->pollset.ps, pollcb->nelts, (int)timeout); 406#else 407 ret = poll(pollcb->pollset.ps, pollcb->nelts, timeout); 408#endif 409 if (ret < 0) { 410 return apr_get_netos_error(); 411 } 412 else if (ret == 0) { 413 return APR_TIMEUP; 414 } 415 else { 416 for (i = 0; i < pollcb->nelts; i++) { 417 if (pollcb->pollset.ps[i].revents != 0) { 418 apr_pollfd_t *pollfd = pollcb->copyset[i]; 419 pollfd->rtnevents = get_revent(pollcb->pollset.ps[i].revents); 420 rv = func(baton, pollfd); 421 if (rv) { 422 return rv; 423 } 424 } 425 } 426 } 427 return rv; 428} 429 430static apr_pollcb_provider_t impl_cb = { 431 impl_pollcb_create, 432 impl_pollcb_add, 433 impl_pollcb_remove, 434 impl_pollcb_poll, 435 "poll" 436}; 437 438apr_pollcb_provider_t *apr_pollcb_provider_poll = &impl_cb; 439 440#endif /* HAVE_POLL */ 441