uxpoll.c (18936B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #if defined(_PR_PTHREADS) 7 8 # error "This file should not be compiled" 9 10 #else /* defined(_PR_PTHREADS) */ 11 12 # include "primpl.h" 13 14 # include <sys/time.h> 15 16 # include <fcntl.h> 17 # ifdef _PR_USE_POLL 18 # include <poll.h> 19 # endif 20 21 # if defined(_PR_USE_POLL) 22 static PRInt32 NativeThreadPoll(PRPollDesc* pds, PRIntn npds, 23 PRIntervalTime timeout) { 24 /* 25 * This function is mostly duplicated from ptio.s's PR_Poll(). 26 */ 27 PRInt32 ready = 0; 28 /* 29 * For restarting poll() if it is interrupted by a signal. 30 * We use these variables to figure out how much time has 31 * elapsed and how much of the timeout still remains. 32 */ 33 PRIntn index, msecs; 34 struct pollfd* syspoll = NULL; 35 PRIntervalTime start, elapsed, remaining; 36 37 syspoll = (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd)); 38 if (NULL == syspoll) { 39 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 40 return -1; 41 } 42 for (index = 0; index < npds; ++index) { 43 PRFileDesc* bottom; 44 PRInt16 in_flags_read = 0, in_flags_write = 0; 45 PRInt16 out_flags_read = 0, out_flags_write = 0; 46 47 if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) { 48 if (pds[index].in_flags & PR_POLL_READ) { 49 in_flags_read = (pds[index].fd->methods->poll)( 50 pds[index].fd, pds[index].in_flags & ~PR_POLL_WRITE, 51 &out_flags_read); 52 } 53 if (pds[index].in_flags & PR_POLL_WRITE) { 54 in_flags_write = (pds[index].fd->methods->poll)( 55 pds[index].fd, pds[index].in_flags & ~PR_POLL_READ, 56 &out_flags_write); 57 } 58 if ((0 != (in_flags_read & out_flags_read)) || 59 (0 != (in_flags_write & out_flags_write))) { 60 /* this one is ready right now */ 61 if (0 == ready) { 62 /* 63 * We will return without calling the system 64 * poll function. So zero the out_flags 65 * fields of all the poll descriptors before 66 * this one. 67 */ 68 int i; 69 for (i = 0; i < index; i++) { 70 pds[i].out_flags = 0; 71 } 72 } 73 ready += 1; 74 pds[index].out_flags = out_flags_read | out_flags_write; 75 } else { 76 pds[index].out_flags = 0; /* pre-condition */ 77 /* now locate the NSPR layer at the bottom of the stack */ 78 bottom = PR_GetIdentitiesLayer(pds[index].fd, PR_NSPR_IO_LAYER); 79 PR_ASSERT(NULL != bottom); /* what to do about that? */ 80 if ((NULL != bottom) && (_PR_FILEDESC_OPEN == bottom->secret->state)) { 81 if (0 == ready) { 82 syspoll[index].fd = bottom->secret->md.osfd; 83 syspoll[index].events = 0; /* pre-condition */ 84 if (in_flags_read & PR_POLL_READ) { 85 pds[index].out_flags |= _PR_POLL_READ_SYS_READ; 86 syspoll[index].events |= POLLIN; 87 } 88 if (in_flags_read & PR_POLL_WRITE) { 89 pds[index].out_flags |= _PR_POLL_READ_SYS_WRITE; 90 syspoll[index].events |= POLLOUT; 91 } 92 if (in_flags_write & PR_POLL_READ) { 93 pds[index].out_flags |= _PR_POLL_WRITE_SYS_READ; 94 syspoll[index].events |= POLLIN; 95 } 96 if (in_flags_write & PR_POLL_WRITE) { 97 pds[index].out_flags |= _PR_POLL_WRITE_SYS_WRITE; 98 syspoll[index].events |= POLLOUT; 99 } 100 if (pds[index].in_flags & PR_POLL_EXCEPT) { 101 syspoll[index].events |= POLLPRI; 102 } 103 } 104 } else { 105 if (0 == ready) { 106 int i; 107 for (i = 0; i < index; i++) { 108 pds[i].out_flags = 0; 109 } 110 } 111 ready += 1; /* this will cause an abrupt return */ 112 pds[index].out_flags = PR_POLL_NVAL; /* bogii */ 113 } 114 } 115 } else { 116 /* make poll() ignore this entry */ 117 syspoll[index].fd = -1; 118 syspoll[index].events = 0; 119 pds[index].out_flags = 0; 120 } 121 } 122 123 if (0 == ready) { 124 switch (timeout) { 125 case PR_INTERVAL_NO_WAIT: 126 msecs = 0; 127 break; 128 case PR_INTERVAL_NO_TIMEOUT: 129 msecs = -1; 130 break; 131 default: 132 msecs = PR_IntervalToMilliseconds(timeout); 133 start = PR_IntervalNow(); 134 } 135 136 retry: 137 ready = _MD_POLL(syspoll, npds, msecs); 138 if (-1 == ready) { 139 PRIntn oserror = errno; 140 141 if (EINTR == oserror) { 142 if (timeout == PR_INTERVAL_NO_TIMEOUT) { 143 goto retry; 144 } else if (timeout == PR_INTERVAL_NO_WAIT) { 145 ready = 0; 146 } else { 147 elapsed = (PRIntervalTime)(PR_IntervalNow() - start); 148 if (elapsed > timeout) { 149 ready = 0; /* timed out */ 150 } else { 151 remaining = timeout - elapsed; 152 msecs = PR_IntervalToMilliseconds(remaining); 153 goto retry; 154 } 155 } 156 } else { 157 _PR_MD_MAP_POLL_ERROR(oserror); 158 } 159 } else if (ready > 0) { 160 for (index = 0; index < npds; ++index) { 161 PRInt16 out_flags = 0; 162 if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) { 163 if (0 != syspoll[index].revents) { 164 /* 165 ** Set up the out_flags so that it contains the 166 ** bits that the highest layer thinks are nice 167 ** to have. Then the client of that layer will 168 ** call the appropriate I/O function and maybe 169 ** the protocol will make progress. 170 */ 171 if (syspoll[index].revents & POLLIN) { 172 if (pds[index].out_flags & _PR_POLL_READ_SYS_READ) { 173 out_flags |= PR_POLL_READ; 174 } 175 if (pds[index].out_flags & _PR_POLL_WRITE_SYS_READ) { 176 out_flags |= PR_POLL_WRITE; 177 } 178 } 179 if (syspoll[index].revents & POLLOUT) { 180 if (pds[index].out_flags & _PR_POLL_READ_SYS_WRITE) { 181 out_flags |= PR_POLL_READ; 182 } 183 if (pds[index].out_flags & _PR_POLL_WRITE_SYS_WRITE) { 184 out_flags |= PR_POLL_WRITE; 185 } 186 } 187 if (syspoll[index].revents & POLLPRI) { 188 out_flags |= PR_POLL_EXCEPT; 189 } 190 if (syspoll[index].revents & POLLERR) { 191 out_flags |= PR_POLL_ERR; 192 } 193 if (syspoll[index].revents & POLLNVAL) { 194 out_flags |= PR_POLL_NVAL; 195 } 196 if (syspoll[index].revents & POLLHUP) { 197 out_flags |= PR_POLL_HUP; 198 } 199 } 200 } 201 pds[index].out_flags = out_flags; 202 } 203 } 204 } 205 206 PR_DELETE(syspoll); 207 return ready; 208 209 } /* NativeThreadPoll */ 210 # endif /* defined(_PR_USE_POLL) */ 211 212 # if !defined(_PR_USE_POLL) 213 static PRInt32 NativeThreadSelect(PRPollDesc* pds, PRIntn npds, 214 PRIntervalTime timeout) { 215 /* 216 * This code is almost a duplicate of w32poll.c's _PR_MD_PR_POLL(). 217 */ 218 fd_set rd, wt, ex; 219 PRFileDesc* bottom; 220 PRPollDesc *pd, *epd; 221 PRInt32 maxfd = -1, ready, err; 222 PRIntervalTime remaining, elapsed, start; 223 224 struct timeval tv, *tvp = NULL; 225 226 FD_ZERO(&rd); 227 FD_ZERO(&wt); 228 FD_ZERO(&ex); 229 230 ready = 0; 231 for (pd = pds, epd = pd + npds; pd < epd; pd++) { 232 PRInt16 in_flags_read = 0, in_flags_write = 0; 233 PRInt16 out_flags_read = 0, out_flags_write = 0; 234 235 if ((NULL != pd->fd) && (0 != pd->in_flags)) { 236 if (pd->in_flags & PR_POLL_READ) { 237 in_flags_read = (pd->fd->methods->poll)( 238 pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); 239 } 240 if (pd->in_flags & PR_POLL_WRITE) { 241 in_flags_write = (pd->fd->methods->poll)( 242 pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); 243 } 244 if ((0 != (in_flags_read & out_flags_read)) || 245 (0 != (in_flags_write & out_flags_write))) { 246 /* this one's ready right now */ 247 if (0 == ready) { 248 /* 249 * We will have to return without calling the 250 * system poll/select function. So zero the 251 * out_flags fields of all the poll descriptors 252 * before this one. 253 */ 254 PRPollDesc* prev; 255 for (prev = pds; prev < pd; prev++) { 256 prev->out_flags = 0; 257 } 258 } 259 ready += 1; 260 pd->out_flags = out_flags_read | out_flags_write; 261 } else { 262 pd->out_flags = 0; /* pre-condition */ 263 264 /* make sure this is an NSPR supported stack */ 265 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); 266 PR_ASSERT(NULL != bottom); /* what to do about that? */ 267 if ((NULL != bottom) && (_PR_FILEDESC_OPEN == bottom->secret->state)) { 268 if (0 == ready) { 269 PRInt32 osfd = bottom->secret->md.osfd; 270 if (osfd > maxfd) { 271 maxfd = osfd; 272 } 273 if (in_flags_read & PR_POLL_READ) { 274 pd->out_flags |= _PR_POLL_READ_SYS_READ; 275 FD_SET(osfd, &rd); 276 } 277 if (in_flags_read & PR_POLL_WRITE) { 278 pd->out_flags |= _PR_POLL_READ_SYS_WRITE; 279 FD_SET(osfd, &wt); 280 } 281 if (in_flags_write & PR_POLL_READ) { 282 pd->out_flags |= _PR_POLL_WRITE_SYS_READ; 283 FD_SET(osfd, &rd); 284 } 285 if (in_flags_write & PR_POLL_WRITE) { 286 pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; 287 FD_SET(osfd, &wt); 288 } 289 if (pd->in_flags & PR_POLL_EXCEPT) { 290 FD_SET(osfd, &ex); 291 } 292 } 293 } else { 294 if (0 == ready) { 295 PRPollDesc* prev; 296 for (prev = pds; prev < pd; prev++) { 297 prev->out_flags = 0; 298 } 299 } 300 ready += 1; /* this will cause an abrupt return */ 301 pd->out_flags = PR_POLL_NVAL; /* bogii */ 302 } 303 } 304 } else { 305 pd->out_flags = 0; 306 } 307 } 308 309 if (0 != ready) { 310 return ready; /* no need to block */ 311 } 312 313 remaining = timeout; 314 start = PR_IntervalNow(); 315 316 retry: 317 if (timeout != PR_INTERVAL_NO_TIMEOUT) { 318 PRInt32 ticksPerSecond = PR_TicksPerSecond(); 319 tv.tv_sec = remaining / ticksPerSecond; 320 tv.tv_usec = PR_IntervalToMicroseconds(remaining % ticksPerSecond); 321 tvp = &tv; 322 } 323 324 ready = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp); 325 326 if (ready == -1 && errno == EINTR) { 327 if (timeout == PR_INTERVAL_NO_TIMEOUT) { 328 goto retry; 329 } else { 330 elapsed = (PRIntervalTime)(PR_IntervalNow() - start); 331 if (elapsed > timeout) { 332 ready = 0; /* timed out */ 333 } else { 334 remaining = timeout - elapsed; 335 goto retry; 336 } 337 } 338 } 339 340 /* 341 ** Now to unravel the select sets back into the client's poll 342 ** descriptor list. Is this possibly an area for pissing away 343 ** a few cycles or what? 344 */ 345 if (ready > 0) { 346 ready = 0; 347 for (pd = pds, epd = pd + npds; pd < epd; pd++) { 348 PRInt16 out_flags = 0; 349 if ((NULL != pd->fd) && (0 != pd->in_flags)) { 350 PRInt32 osfd; 351 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); 352 PR_ASSERT(NULL != bottom); 353 354 osfd = bottom->secret->md.osfd; 355 356 if (FD_ISSET(osfd, &rd)) { 357 if (pd->out_flags & _PR_POLL_READ_SYS_READ) { 358 out_flags |= PR_POLL_READ; 359 } 360 if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) { 361 out_flags |= PR_POLL_WRITE; 362 } 363 } 364 if (FD_ISSET(osfd, &wt)) { 365 if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) { 366 out_flags |= PR_POLL_READ; 367 } 368 if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) { 369 out_flags |= PR_POLL_WRITE; 370 } 371 } 372 if (FD_ISSET(osfd, &ex)) { 373 out_flags |= PR_POLL_EXCEPT; 374 } 375 } 376 pd->out_flags = out_flags; 377 if (out_flags) { 378 ready++; 379 } 380 } 381 PR_ASSERT(ready > 0); 382 } else if (ready < 0) { 383 err = _MD_ERRNO(); 384 if (err == EBADF) { 385 /* Find the bad fds */ 386 ready = 0; 387 for (pd = pds, epd = pd + npds; pd < epd; pd++) { 388 pd->out_flags = 0; 389 if ((NULL != pd->fd) && (0 != pd->in_flags)) { 390 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); 391 if (fcntl(bottom->secret->md.osfd, F_GETFL, 0) == -1) { 392 pd->out_flags = PR_POLL_NVAL; 393 ready++; 394 } 395 } 396 } 397 PR_ASSERT(ready > 0); 398 } else { 399 _PR_MD_MAP_SELECT_ERROR(err); 400 } 401 } 402 403 return ready; 404 } /* NativeThreadSelect */ 405 # endif /* !defined(_PR_USE_POLL) */ 406 407 static PRInt32 LocalThreads(PRPollDesc* pds, PRIntn npds, 408 PRIntervalTime timeout) { 409 PRPollDesc *pd, *epd; 410 PRInt32 ready, pdcnt; 411 _PRUnixPollDesc *unixpds, *unixpd; 412 413 /* 414 * XXX 415 * PRPollDesc has a PRFileDesc field, fd, while the IOQ 416 * is a list of PRPollQueue structures, each of which contains 417 * a _PRUnixPollDesc. A _PRUnixPollDesc struct contains 418 * the OS file descriptor, osfd, and not a PRFileDesc. 419 * So, we have allocate memory for _PRUnixPollDesc structures, 420 * copy the flags information from the pds list and have pq 421 * point to this list of _PRUnixPollDesc structures. 422 * 423 * It would be better if the memory allocation can be avoided. 424 */ 425 426 unixpd = unixpds = 427 (_PRUnixPollDesc*)PR_MALLOC(npds * sizeof(_PRUnixPollDesc)); 428 if (NULL == unixpds) { 429 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 430 return -1; 431 } 432 433 ready = 0; 434 for (pdcnt = 0, pd = pds, epd = pd + npds; pd < epd; pd++) { 435 PRFileDesc* bottom; 436 PRInt16 in_flags_read = 0, in_flags_write = 0; 437 PRInt16 out_flags_read = 0, out_flags_write = 0; 438 439 if ((NULL != pd->fd) && (0 != pd->in_flags)) { 440 if (pd->in_flags & PR_POLL_READ) { 441 in_flags_read = (pd->fd->methods->poll)( 442 pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); 443 } 444 if (pd->in_flags & PR_POLL_WRITE) { 445 in_flags_write = (pd->fd->methods->poll)( 446 pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); 447 } 448 if ((0 != (in_flags_read & out_flags_read)) || 449 (0 != (in_flags_write & out_flags_write))) { 450 /* this one's ready right now */ 451 if (0 == ready) { 452 /* 453 * We will have to return without calling the 454 * system poll/select function. So zero the 455 * out_flags fields of all the poll descriptors 456 * before this one. 457 */ 458 PRPollDesc* prev; 459 for (prev = pds; prev < pd; prev++) { 460 prev->out_flags = 0; 461 } 462 } 463 ready += 1; 464 pd->out_flags = out_flags_read | out_flags_write; 465 } else { 466 pd->out_flags = 0; /* pre-condition */ 467 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); 468 PR_ASSERT(NULL != bottom); /* what to do about that? */ 469 if ((NULL != bottom) && (_PR_FILEDESC_OPEN == bottom->secret->state)) { 470 if (0 == ready) { 471 unixpd->osfd = bottom->secret->md.osfd; 472 unixpd->in_flags = 0; 473 if (in_flags_read & PR_POLL_READ) { 474 unixpd->in_flags |= _PR_UNIX_POLL_READ; 475 pd->out_flags |= _PR_POLL_READ_SYS_READ; 476 } 477 if (in_flags_read & PR_POLL_WRITE) { 478 unixpd->in_flags |= _PR_UNIX_POLL_WRITE; 479 pd->out_flags |= _PR_POLL_READ_SYS_WRITE; 480 } 481 if (in_flags_write & PR_POLL_READ) { 482 unixpd->in_flags |= _PR_UNIX_POLL_READ; 483 pd->out_flags |= _PR_POLL_WRITE_SYS_READ; 484 } 485 if (in_flags_write & PR_POLL_WRITE) { 486 unixpd->in_flags |= _PR_UNIX_POLL_WRITE; 487 pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; 488 } 489 if ((in_flags_read | in_flags_write) & PR_POLL_EXCEPT) { 490 unixpd->in_flags |= _PR_UNIX_POLL_EXCEPT; 491 } 492 unixpd++; 493 pdcnt++; 494 } 495 } else { 496 if (0 == ready) { 497 PRPollDesc* prev; 498 for (prev = pds; prev < pd; prev++) { 499 prev->out_flags = 0; 500 } 501 } 502 ready += 1; /* this will cause an abrupt return */ 503 pd->out_flags = PR_POLL_NVAL; /* bogii */ 504 } 505 } 506 } 507 } 508 509 if (0 != ready) { 510 /* no need to block */ 511 PR_DELETE(unixpds); 512 return ready; 513 } 514 515 ready = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout); 516 517 /* 518 * Copy the out_flags from the _PRUnixPollDesc structures to the 519 * user's PRPollDesc structures and free the allocated memory 520 */ 521 unixpd = unixpds; 522 for (pd = pds, epd = pd + npds; pd < epd; pd++) { 523 PRInt16 out_flags = 0; 524 if ((NULL != pd->fd) && (0 != pd->in_flags)) { 525 /* 526 * take errors from the poll operation, 527 * the R/W bits from the request 528 */ 529 if (0 != unixpd->out_flags) { 530 if (unixpd->out_flags & _PR_UNIX_POLL_READ) { 531 if (pd->out_flags & _PR_POLL_READ_SYS_READ) { 532 out_flags |= PR_POLL_READ; 533 } 534 if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) { 535 out_flags |= PR_POLL_WRITE; 536 } 537 } 538 if (unixpd->out_flags & _PR_UNIX_POLL_WRITE) { 539 if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) { 540 out_flags |= PR_POLL_READ; 541 } 542 if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) { 543 out_flags |= PR_POLL_WRITE; 544 } 545 } 546 if (unixpd->out_flags & _PR_UNIX_POLL_EXCEPT) { 547 out_flags |= PR_POLL_EXCEPT; 548 } 549 if (unixpd->out_flags & _PR_UNIX_POLL_ERR) { 550 out_flags |= PR_POLL_ERR; 551 } 552 if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) { 553 out_flags |= PR_POLL_NVAL; 554 } 555 if (unixpd->out_flags & _PR_UNIX_POLL_HUP) { 556 out_flags |= PR_POLL_HUP; 557 } 558 } 559 unixpd++; 560 } 561 pd->out_flags = out_flags; 562 } 563 564 PR_DELETE(unixpds); 565 566 return ready; 567 } /* LocalThreads */ 568 569 # if defined(_PR_USE_POLL) 570 # define NativeThreads NativeThreadPoll 571 # else 572 # define NativeThreads NativeThreadSelect 573 # endif 574 575 PRInt32 _MD_pr_poll(PRPollDesc* pds, PRIntn npds, PRIntervalTime timeout) { 576 PRInt32 rv = 0; 577 PRThread* me = _PR_MD_CURRENT_THREAD(); 578 579 if (_PR_PENDING_INTERRUPT(me)) { 580 me->flags &= ~_PR_INTERRUPT; 581 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 582 return -1; 583 } 584 if (0 == npds) { 585 PR_Sleep(timeout); 586 } else if (_PR_IS_NATIVE_THREAD(me)) { 587 rv = NativeThreads(pds, npds, timeout); 588 } else { 589 rv = LocalThreads(pds, npds, timeout); 590 } 591 592 return rv; 593 } /* _MD_pr_poll */ 594 595 #endif /* defined(_PR_PTHREADS) */ 596 597 /* uxpoll.c */