| OLD | NEW |
| (Empty) |
| 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 #include "primpl.h" | |
| 7 | |
| 8 #include <string.h> | |
| 9 #include <signal.h> | |
| 10 #include <unistd.h> | |
| 11 #include <fcntl.h> | |
| 12 #include <sys/types.h> | |
| 13 #include <sys/socket.h> | |
| 14 #include <sys/time.h> | |
| 15 #include <sys/ioctl.h> | |
| 16 #include <sys/mman.h> | |
| 17 #include <unistd.h> | |
| 18 #include <sys/utsname.h> | |
| 19 | |
| 20 #ifdef _PR_POLL_AVAILABLE | |
| 21 #include <poll.h> | |
| 22 #endif | |
| 23 | |
| 24 /* To get FIONREAD */ | |
| 25 #if defined(UNIXWARE) | |
| 26 #include <sys/filio.h> | |
| 27 #endif | |
| 28 | |
| 29 #if defined(NTO) | |
| 30 #include <sys/statvfs.h> | |
| 31 #endif | |
| 32 | |
| 33 /* | |
| 34 * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or | |
| 35 * PRInt32* pointer to a _PRSockLen_t* pointer. | |
| 36 */ | |
| 37 #if defined(HAVE_SOCKLEN_T) \ | |
| 38 || (defined(__GLIBC__) && __GLIBC__ >= 2) | |
| 39 #define _PRSockLen_t socklen_t | |
| 40 #elif defined(IRIX) || defined(HPUX) || defined(OSF1) || defined(SOLARIS) \ | |
| 41 || defined(AIX4_1) || defined(LINUX) \ | |
| 42 || defined(BSDI) || defined(SCO) \ | |
| 43 || defined(DARWIN) \ | |
| 44 || defined(QNX) | |
| 45 #define _PRSockLen_t int | |
| 46 #elif (defined(AIX) && !defined(AIX4_1)) || defined(FREEBSD) \ | |
| 47 || defined(NETBSD) || defined(OPENBSD) || defined(UNIXWARE) \ | |
| 48 || defined(DGUX) || defined(NTO) || defined(RISCOS) | |
| 49 #define _PRSockLen_t size_t | |
| 50 #else | |
| 51 #error "Cannot determine architecture" | |
| 52 #endif | |
| 53 | |
| 54 /* | |
| 55 ** Global lock variable used to bracket calls into rusty libraries that | |
| 56 ** aren't thread safe (like libc, libX, etc). | |
| 57 */ | |
| 58 static PRLock *_pr_rename_lock = NULL; | |
| 59 static PRMonitor *_pr_Xfe_mon = NULL; | |
| 60 | |
| 61 static PRInt64 minus_one; | |
| 62 | |
| 63 sigset_t timer_set; | |
| 64 | |
| 65 #if !defined(_PR_PTHREADS) | |
| 66 | |
| 67 static sigset_t empty_set; | |
| 68 | |
| 69 #ifdef SOLARIS | |
| 70 #include <sys/file.h> | |
| 71 #include <sys/filio.h> | |
| 72 #endif | |
| 73 | |
| 74 #ifndef PIPE_BUF | |
| 75 #define PIPE_BUF 512 | |
| 76 #endif | |
| 77 | |
| 78 /* | |
| 79 * _nspr_noclock - if set clock interrupts are disabled | |
| 80 */ | |
| 81 int _nspr_noclock = 1; | |
| 82 | |
| 83 #ifdef IRIX | |
| 84 extern PRInt32 _nspr_terminate_on_error; | |
| 85 #endif | |
| 86 | |
| 87 /* | |
| 88 * There is an assertion in this code that NSPR's definition of PRIOVec | |
| 89 * is bit compatible with UNIX' definition of a struct iovec. This is | |
| 90 * applicable to the 'writev()' operations where the types are casually | |
| 91 * cast to avoid warnings. | |
| 92 */ | |
| 93 | |
| 94 int _pr_md_pipefd[2] = { -1, -1 }; | |
| 95 static char _pr_md_pipebuf[PIPE_BUF]; | |
| 96 static PRInt32 local_io_wait(PRInt32 osfd, PRInt32 wait_flag, | |
| 97 PRIntervalTime timeout); | |
| 98 | |
| 99 _PRInterruptTable _pr_interruptTable[] = { | |
| 100 { | |
| 101 "clock", _PR_MISSED_CLOCK, _PR_ClockInterrupt, }, | |
| 102 { | |
| 103 0 } | |
| 104 }; | |
| 105 | |
| 106 void _MD_unix_init_running_cpu(_PRCPU *cpu) | |
| 107 { | |
| 108 PR_INIT_CLIST(&(cpu->md.md_unix.ioQ)); | |
| 109 cpu->md.md_unix.ioq_max_osfd = -1; | |
| 110 cpu->md.md_unix.ioq_timeout = PR_INTERVAL_NO_TIMEOUT; | |
| 111 } | |
| 112 | |
| 113 PRStatus _MD_open_dir(_MDDir *d, const char *name) | |
| 114 { | |
| 115 int err; | |
| 116 | |
| 117 d->d = opendir(name); | |
| 118 if (!d->d) { | |
| 119 err = _MD_ERRNO(); | |
| 120 _PR_MD_MAP_OPENDIR_ERROR(err); | |
| 121 return PR_FAILURE; | |
| 122 } | |
| 123 return PR_SUCCESS; | |
| 124 } | |
| 125 | |
| 126 PRInt32 _MD_close_dir(_MDDir *d) | |
| 127 { | |
| 128 int rv = 0, err; | |
| 129 | |
| 130 if (d->d) { | |
| 131 rv = closedir(d->d); | |
| 132 if (rv == -1) { | |
| 133 err = _MD_ERRNO(); | |
| 134 _PR_MD_MAP_CLOSEDIR_ERROR(err); | |
| 135 } | |
| 136 } | |
| 137 return rv; | |
| 138 } | |
| 139 | |
| 140 char * _MD_read_dir(_MDDir *d, PRIntn flags) | |
| 141 { | |
| 142 struct dirent *de; | |
| 143 int err; | |
| 144 | |
| 145 for (;;) { | |
| 146 /* | |
| 147 * XXX: readdir() is not MT-safe. There is an MT-safe version | |
| 148 * readdir_r() on some systems. | |
| 149 */ | |
| 150 _MD_ERRNO() = 0; | |
| 151 de = readdir(d->d); | |
| 152 if (!de) { | |
| 153 err = _MD_ERRNO(); | |
| 154 _PR_MD_MAP_READDIR_ERROR(err); | |
| 155 return 0; | |
| 156 } | |
| 157 if ((flags & PR_SKIP_DOT) && | |
| 158 (de->d_name[0] == '.') && (de->d_name[1] == 0)) | |
| 159 continue; | |
| 160 if ((flags & PR_SKIP_DOT_DOT) && | |
| 161 (de->d_name[0] == '.') && (de->d_name[1] == '.') && | |
| 162 (de->d_name[2] == 0)) | |
| 163 continue; | |
| 164 if ((flags & PR_SKIP_HIDDEN) && (de->d_name[0] == '.')) | |
| 165 continue; | |
| 166 break; | |
| 167 } | |
| 168 return de->d_name; | |
| 169 } | |
| 170 | |
| 171 PRInt32 _MD_delete(const char *name) | |
| 172 { | |
| 173 PRInt32 rv, err; | |
| 174 #ifdef UNIXWARE | |
| 175 sigset_t set, oset; | |
| 176 #endif | |
| 177 | |
| 178 #ifdef UNIXWARE | |
| 179 sigfillset(&set); | |
| 180 sigprocmask(SIG_SETMASK, &set, &oset); | |
| 181 #endif | |
| 182 rv = unlink(name); | |
| 183 #ifdef UNIXWARE | |
| 184 sigprocmask(SIG_SETMASK, &oset, NULL); | |
| 185 #endif | |
| 186 if (rv == -1) { | |
| 187 err = _MD_ERRNO(); | |
| 188 _PR_MD_MAP_UNLINK_ERROR(err); | |
| 189 } | |
| 190 return(rv); | |
| 191 } | |
| 192 | |
| 193 PRInt32 _MD_rename(const char *from, const char *to) | |
| 194 { | |
| 195 PRInt32 rv = -1, err; | |
| 196 | |
| 197 /* | |
| 198 ** This is trying to enforce the semantics of WINDOZE' rename | |
| 199 ** operation. That means one is not allowed to rename over top | |
| 200 ** of an existing file. Holding a lock across these two function | |
| 201 ** and the open function is known to be a bad idea, but .... | |
| 202 */ | |
| 203 if (NULL != _pr_rename_lock) | |
| 204 PR_Lock(_pr_rename_lock); | |
| 205 if (0 == access(to, F_OK)) | |
| 206 PR_SetError(PR_FILE_EXISTS_ERROR, 0); | |
| 207 else | |
| 208 { | |
| 209 rv = rename(from, to); | |
| 210 if (rv < 0) { | |
| 211 err = _MD_ERRNO(); | |
| 212 _PR_MD_MAP_RENAME_ERROR(err); | |
| 213 } | |
| 214 } | |
| 215 if (NULL != _pr_rename_lock) | |
| 216 PR_Unlock(_pr_rename_lock); | |
| 217 return rv; | |
| 218 } | |
| 219 | |
| 220 PRInt32 _MD_access(const char *name, PRAccessHow how) | |
| 221 { | |
| 222 PRInt32 rv, err; | |
| 223 int amode; | |
| 224 | |
| 225 switch (how) { | |
| 226 case PR_ACCESS_WRITE_OK: | |
| 227 amode = W_OK; | |
| 228 break; | |
| 229 case PR_ACCESS_READ_OK: | |
| 230 amode = R_OK; | |
| 231 break; | |
| 232 case PR_ACCESS_EXISTS: | |
| 233 amode = F_OK; | |
| 234 break; | |
| 235 default: | |
| 236 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 237 rv = -1; | |
| 238 goto done; | |
| 239 } | |
| 240 rv = access(name, amode); | |
| 241 | |
| 242 if (rv < 0) { | |
| 243 err = _MD_ERRNO(); | |
| 244 _PR_MD_MAP_ACCESS_ERROR(err); | |
| 245 } | |
| 246 | |
| 247 done: | |
| 248 return(rv); | |
| 249 } | |
| 250 | |
| 251 PRInt32 _MD_mkdir(const char *name, PRIntn mode) | |
| 252 { | |
| 253 int rv, err; | |
| 254 | |
| 255 /* | |
| 256 ** This lock is used to enforce rename semantics as described | |
| 257 ** in PR_Rename. Look there for more fun details. | |
| 258 */ | |
| 259 if (NULL !=_pr_rename_lock) | |
| 260 PR_Lock(_pr_rename_lock); | |
| 261 rv = mkdir(name, mode); | |
| 262 if (rv < 0) { | |
| 263 err = _MD_ERRNO(); | |
| 264 _PR_MD_MAP_MKDIR_ERROR(err); | |
| 265 } | |
| 266 if (NULL !=_pr_rename_lock) | |
| 267 PR_Unlock(_pr_rename_lock); | |
| 268 return rv; | |
| 269 } | |
| 270 | |
| 271 PRInt32 _MD_rmdir(const char *name) | |
| 272 { | |
| 273 int rv, err; | |
| 274 | |
| 275 rv = rmdir(name); | |
| 276 if (rv == -1) { | |
| 277 err = _MD_ERRNO(); | |
| 278 _PR_MD_MAP_RMDIR_ERROR(err); | |
| 279 } | |
| 280 return rv; | |
| 281 } | |
| 282 | |
| 283 PRInt32 _MD_read(PRFileDesc *fd, void *buf, PRInt32 amount) | |
| 284 { | |
| 285 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 286 PRInt32 rv, err; | |
| 287 #ifndef _PR_USE_POLL | |
| 288 fd_set rd; | |
| 289 #else | |
| 290 struct pollfd pfd; | |
| 291 #endif /* _PR_USE_POLL */ | |
| 292 PRInt32 osfd = fd->secret->md.osfd; | |
| 293 | |
| 294 #ifndef _PR_USE_POLL | |
| 295 FD_ZERO(&rd); | |
| 296 FD_SET(osfd, &rd); | |
| 297 #else | |
| 298 pfd.fd = osfd; | |
| 299 pfd.events = POLLIN; | |
| 300 #endif /* _PR_USE_POLL */ | |
| 301 while ((rv = read(osfd,buf,amount)) == -1) { | |
| 302 err = _MD_ERRNO(); | |
| 303 if ((err == EAGAIN) || (err == EWOULDBLOCK)) { | |
| 304 if (fd->secret->nonblocking) { | |
| 305 break; | |
| 306 } | |
| 307 if (!_PR_IS_NATIVE_THREAD(me)) { | |
| 308 if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, | |
| 309
PR_INTERVAL_NO_TIMEOUT)) < 0) | |
| 310 goto done;
| |
| 311 } else { | |
| 312 #ifndef _PR_USE_POLL | |
| 313 while ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, NULL)) | |
| 314 == -1 && (err = _MD_ERRNO()) == EINTR) { | |
| 315 /* retry _MD_SELECT() if it is interrupted */ | |
| 316 } | |
| 317 #else /* _PR_USE_POLL */ | |
| 318 while ((rv = _MD_POLL(&pfd, 1, -1)) | |
| 319 == -1 && (err = _MD_ERRNO()) == EINTR) { | |
| 320 /* retry _MD_POLL() if it is interrupted */ | |
| 321 } | |
| 322 #endif /* _PR_USE_POLL */ | |
| 323 if (rv == -1) { | |
| 324 break; | |
| 325 } | |
| 326 } | |
| 327 if (_PR_PENDING_INTERRUPT(me)) | |
| 328 break; | |
| 329 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ | |
| 330 continue; | |
| 331 } else { | |
| 332 break; | |
| 333 } | |
| 334 } | |
| 335 if (rv < 0) { | |
| 336 if (_PR_PENDING_INTERRUPT(me)) { | |
| 337 me->flags &= ~_PR_INTERRUPT; | |
| 338 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
| 339 } else { | |
| 340 _PR_MD_MAP_READ_ERROR(err); | |
| 341 } | |
| 342 } | |
| 343 done: | |
| 344 return(rv); | |
| 345 } | |
| 346 | |
| 347 PRInt32 _MD_write(PRFileDesc *fd, const void *buf, PRInt32 amount) | |
| 348 { | |
| 349 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 350 PRInt32 rv, err; | |
| 351 #ifndef _PR_USE_POLL | |
| 352 fd_set wd; | |
| 353 #else | |
| 354 struct pollfd pfd; | |
| 355 #endif /* _PR_USE_POLL */ | |
| 356 PRInt32 osfd = fd->secret->md.osfd; | |
| 357 | |
| 358 #ifndef _PR_USE_POLL | |
| 359 FD_ZERO(&wd); | |
| 360 FD_SET(osfd, &wd); | |
| 361 #else | |
| 362 pfd.fd = osfd; | |
| 363 pfd.events = POLLOUT; | |
| 364 #endif /* _PR_USE_POLL */ | |
| 365 while ((rv = write(osfd,buf,amount)) == -1) { | |
| 366 err = _MD_ERRNO(); | |
| 367 if ((err == EAGAIN) || (err == EWOULDBLOCK)) { | |
| 368 if (fd->secret->nonblocking) { | |
| 369 break; | |
| 370 } | |
| 371 if (!_PR_IS_NATIVE_THREAD(me)) { | |
| 372 if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, | |
| 373
PR_INTERVAL_NO_TIMEOUT)) < 0) | |
| 374 goto done; | |
| 375 } else { | |
| 376 #ifndef _PR_USE_POLL | |
| 377 while ((rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL, NULL)) | |
| 378 == -1 && (err = _MD_ERRNO()) == EINTR) { | |
| 379 /* retry _MD_SELECT() if it is interrupted */ | |
| 380 } | |
| 381 #else /* _PR_USE_POLL */ | |
| 382 while ((rv = _MD_POLL(&pfd, 1, -1)) | |
| 383 == -1 && (err = _MD_ERRNO()) == EINTR) { | |
| 384 /* retry _MD_POLL() if it is interrupted */ | |
| 385 } | |
| 386 #endif /* _PR_USE_POLL */ | |
| 387 if (rv == -1) { | |
| 388 break; | |
| 389 } | |
| 390 } | |
| 391 if (_PR_PENDING_INTERRUPT(me)) | |
| 392 break; | |
| 393 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ | |
| 394 continue; | |
| 395 } else { | |
| 396 break; | |
| 397 } | |
| 398 } | |
| 399 if (rv < 0) { | |
| 400 if (_PR_PENDING_INTERRUPT(me)) { | |
| 401 me->flags &= ~_PR_INTERRUPT; | |
| 402 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
| 403 } else { | |
| 404 _PR_MD_MAP_WRITE_ERROR(err); | |
| 405 } | |
| 406 } | |
| 407 done: | |
| 408 return(rv); | |
| 409 } | |
| 410 | |
| 411 PRInt32 _MD_fsync(PRFileDesc *fd) | |
| 412 { | |
| 413 PRInt32 rv, err; | |
| 414 | |
| 415 rv = fsync(fd->secret->md.osfd); | |
| 416 if (rv == -1) { | |
| 417 err = _MD_ERRNO(); | |
| 418 _PR_MD_MAP_FSYNC_ERROR(err); | |
| 419 } | |
| 420 return(rv); | |
| 421 } | |
| 422 | |
| 423 PRInt32 _MD_close(PRInt32 osfd) | |
| 424 { | |
| 425 PRInt32 rv, err; | |
| 426 | |
| 427 rv = close(osfd); | |
| 428 if (rv == -1) { | |
| 429 err = _MD_ERRNO(); | |
| 430 _PR_MD_MAP_CLOSE_ERROR(err); | |
| 431 } | |
| 432 return(rv); | |
| 433 } | |
| 434 | |
| 435 PRInt32 _MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto) | |
| 436 { | |
| 437 PRInt32 osfd, err; | |
| 438 | |
| 439 osfd = socket(domain, type, proto); | |
| 440 | |
| 441 if (osfd == -1) { | |
| 442 err = _MD_ERRNO(); | |
| 443 _PR_MD_MAP_SOCKET_ERROR(err); | |
| 444 return(osfd); | |
| 445 } | |
| 446 | |
| 447 return(osfd); | |
| 448 } | |
| 449 | |
| 450 PRInt32 _MD_socketavailable(PRFileDesc *fd) | |
| 451 { | |
| 452 PRInt32 result; | |
| 453 | |
| 454 if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) { | |
| 455 _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO()); | |
| 456 return -1; | |
| 457 } | |
| 458 return result; | |
| 459 } | |
| 460 | |
| 461 PRInt64 _MD_socketavailable64(PRFileDesc *fd) | |
| 462 { | |
| 463 PRInt64 result; | |
| 464 LL_I2L(result, _MD_socketavailable(fd)); | |
| 465 return result; | |
| 466 } /* _MD_socketavailable64 */ | |
| 467 | |
| 468 #define READ_FD 1 | |
| 469 #define WRITE_FD 2 | |
| 470 | |
| 471 /* | |
| 472 * socket_io_wait -- | |
| 473 * | |
| 474 * wait for socket i/o, periodically checking for interrupt | |
| 475 * | |
| 476 * The first implementation uses select(), for platforms without | |
| 477 * poll(). The second (preferred) implementation uses poll(). | |
| 478 */ | |
| 479 | |
| 480 #ifndef _PR_USE_POLL | |
| 481 | |
| 482 static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type, | |
| 483 PRIntervalTime timeout) | |
| 484 { | |
| 485 PRInt32 rv = -1; | |
| 486 struct timeval tv; | |
| 487 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 488 PRIntervalTime epoch, now, elapsed, remaining; | |
| 489 PRBool wait_for_remaining; | |
| 490 PRInt32 syserror; | |
| 491 fd_set rd_wr; | |
| 492 | |
| 493 switch (timeout) { | |
| 494 case PR_INTERVAL_NO_WAIT: | |
| 495 PR_SetError(PR_IO_TIMEOUT_ERROR, 0); | |
| 496 break; | |
| 497 case PR_INTERVAL_NO_TIMEOUT: | |
| 498 /* | |
| 499 * This is a special case of the 'default' case below. | |
| 500 * Please see the comments there. | |
| 501 */ | |
| 502 tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; | |
| 503 tv.tv_usec = 0; | |
| 504 FD_ZERO(&rd_wr); | |
| 505 do { | |
| 506 FD_SET(osfd, &rd_wr); | |
| 507 if (fd_type == READ_FD) | |
| 508 rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); | |
| 509 else | |
| 510 rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); | |
| 511 if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { | |
| 512 _PR_MD_MAP_SELECT_ERROR(syserror); | |
| 513 break; | |
| 514 } | |
| 515 if (_PR_PENDING_INTERRUPT(me)) { | |
| 516 me->flags &= ~_PR_INTERRUPT; | |
| 517 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
| 518 rv = -1; | |
| 519 break; | |
| 520 } | |
| 521 } while (rv == 0 || (rv == -1 && syserror == EINTR)); | |
| 522 break; | |
| 523 default: | |
| 524 now = epoch = PR_IntervalNow(); | |
| 525 remaining = timeout; | |
| 526 FD_ZERO(&rd_wr); | |
| 527 do { | |
| 528 /* | |
| 529 * We block in _MD_SELECT for at most | |
| 530 * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, | |
| 531 * so that there is an upper limit on the delay | |
| 532 * before the interrupt bit is checked. | |
| 533 */ | |
| 534 wait_for_remaining = PR_TRUE; | |
| 535 tv.tv_sec = PR_IntervalToSeconds(remaining); | |
| 536 if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { | |
| 537 wait_for_remaining = PR_FALSE; | |
| 538 tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; | |
| 539 tv.tv_usec = 0; | |
| 540 } else { | |
| 541 tv.tv_usec = PR_IntervalToMicroseconds( | |
| 542 remaining - | |
| 543 PR_SecondsToInterval(tv.tv_sec)); | |
| 544 } | |
| 545 FD_SET(osfd, &rd_wr); | |
| 546 if (fd_type == READ_FD) | |
| 547 rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); | |
| 548 else | |
| 549 rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); | |
| 550 /* | |
| 551 * we don't consider EINTR a real error | |
| 552 */ | |
| 553 if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { | |
| 554 _PR_MD_MAP_SELECT_ERROR(syserror); | |
| 555 break; | |
| 556 } | |
| 557 if (_PR_PENDING_INTERRUPT(me)) { | |
| 558 me->flags &= ~_PR_INTERRUPT; | |
| 559 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
| 560 rv = -1; | |
| 561 break; | |
| 562 } | |
| 563 /* | |
| 564 * We loop again if _MD_SELECT timed out or got interrupted | |
| 565 * by a signal, and the timeout deadline has not passed yet. | |
| 566 */ | |
| 567 if (rv == 0 || (rv == -1 && syserror == EINTR)) { | |
| 568 /* | |
| 569 * If _MD_SELECT timed out, we know how much time | |
| 570 * we spent in blocking, so we can avoid a | |
| 571 * PR_IntervalNow() call. | |
| 572 */ | |
| 573 if (rv == 0) { | |
| 574 if (wait_for_remaining) { | |
| 575 now += remaining; | |
| 576 } else { | |
| 577 now += PR_SecondsToInterval(tv.tv_sec) | |
| 578 + PR_MicrosecondsToInterval(tv.tv_usec); | |
| 579 } | |
| 580 } else { | |
| 581 now = PR_IntervalNow(); | |
| 582 } | |
| 583 elapsed = (PRIntervalTime) (now - epoch); | |
| 584 if (elapsed >= timeout) { | |
| 585 PR_SetError(PR_IO_TIMEOUT_ERROR, 0); | |
| 586 rv = -1; | |
| 587 break; | |
| 588 } else { | |
| 589 remaining = timeout - elapsed; | |
| 590 } | |
| 591 } | |
| 592 } while (rv == 0 || (rv == -1 && syserror == EINTR)); | |
| 593 break; | |
| 594 } | |
| 595 return(rv); | |
| 596 } | |
| 597 | |
| 598 #else /* _PR_USE_POLL */ | |
| 599 | |
| 600 static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type, | |
| 601 PRIntervalTime timeout) | |
| 602 { | |
| 603 PRInt32 rv = -1; | |
| 604 int msecs; | |
| 605 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 606 PRIntervalTime epoch, now, elapsed, remaining; | |
| 607 PRBool wait_for_remaining; | |
| 608 PRInt32 syserror; | |
| 609 struct pollfd pfd; | |
| 610 | |
| 611 switch (timeout) { | |
| 612 case PR_INTERVAL_NO_WAIT: | |
| 613 PR_SetError(PR_IO_TIMEOUT_ERROR, 0); | |
| 614 break; | |
| 615 case PR_INTERVAL_NO_TIMEOUT: | |
| 616 /* | |
| 617 * This is a special case of the 'default' case below. | |
| 618 * Please see the comments there. | |
| 619 */ | |
| 620 msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; | |
| 621 pfd.fd = osfd; | |
| 622 if (fd_type == READ_FD) { | |
| 623 pfd.events = POLLIN; | |
| 624 } else { | |
| 625 pfd.events = POLLOUT; | |
| 626 } | |
| 627 do { | |
| 628 rv = _MD_POLL(&pfd, 1, msecs); | |
| 629 if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { | |
| 630 _PR_MD_MAP_POLL_ERROR(syserror); | |
| 631 break; | |
| 632 } | |
| 633 /* | |
| 634 * If POLLERR is set, don't process it; retry th
e operation | |
| 635 */ | |
| 636 if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) { | |
| 637 rv = -1; | |
| 638 _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents); | |
| 639 break; | |
| 640 } | |
| 641 if (_PR_PENDING_INTERRUPT(me)) { | |
| 642 me->flags &= ~_PR_INTERRUPT; | |
| 643 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
| 644 rv = -1; | |
| 645 break; | |
| 646 } | |
| 647 } while (rv == 0 || (rv == -1 && syserror == EINTR)); | |
| 648 break; | |
| 649 default: | |
| 650 now = epoch = PR_IntervalNow(); | |
| 651 remaining = timeout; | |
| 652 pfd.fd = osfd; | |
| 653 if (fd_type == READ_FD) { | |
| 654 pfd.events = POLLIN; | |
| 655 } else { | |
| 656 pfd.events = POLLOUT; | |
| 657 } | |
| 658 do { | |
| 659 /* | |
| 660 * We block in _MD_POLL for at most | |
| 661 * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, | |
| 662 * so that there is an upper limit on the delay | |
| 663 * before the interrupt bit is checked. | |
| 664 */ | |
| 665 wait_for_remaining = PR_TRUE; | |
| 666 msecs = PR_IntervalToMilliseconds(remaining); | |
| 667 if (msecs > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) { | |
| 668 wait_for_remaining = PR_FALSE; | |
| 669 msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; | |
| 670 } | |
| 671 rv = _MD_POLL(&pfd, 1, msecs); | |
| 672 /* | |
| 673 * we don't consider EINTR a real error | |
| 674 */ | |
| 675 if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { | |
| 676 _PR_MD_MAP_POLL_ERROR(syserror); | |
| 677 break; | |
| 678 } | |
| 679 if (_PR_PENDING_INTERRUPT(me)) { | |
| 680 me->flags &= ~_PR_INTERRUPT; | |
| 681 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
| 682 rv = -1; | |
| 683 break; | |
| 684 } | |
| 685 /* | |
| 686 * If POLLERR is set, don't process it; retry th
e operation | |
| 687 */ | |
| 688 if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) { | |
| 689 rv = -1; | |
| 690 _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents); | |
| 691 break; | |
| 692 } | |
| 693 /* | |
| 694 * We loop again if _MD_POLL timed out or got interrupted | |
| 695 * by a signal, and the timeout deadline has not passed yet. | |
| 696 */ | |
| 697 if (rv == 0 || (rv == -1 && syserror == EINTR)) { | |
| 698 /* | |
| 699 * If _MD_POLL timed out, we know how much time | |
| 700 * we spent in blocking, so we can avoid a | |
| 701 * PR_IntervalNow() call. | |
| 702 */ | |
| 703 if (rv == 0) { | |
| 704 if (wait_for_remaining) { | |
| 705 now += remaining; | |
| 706 } else { | |
| 707 now += PR_MillisecondsToInterval(msecs); | |
| 708 } | |
| 709 } else { | |
| 710 now = PR_IntervalNow(); | |
| 711 } | |
| 712 elapsed = (PRIntervalTime) (now - epoch); | |
| 713 if (elapsed >= timeout) { | |
| 714 PR_SetError(PR_IO_TIMEOUT_ERROR, 0); | |
| 715 rv = -1; | |
| 716 break; | |
| 717 } else { | |
| 718 remaining = timeout - elapsed; | |
| 719 } | |
| 720 } | |
| 721 } while (rv == 0 || (rv == -1 && syserror == EINTR)); | |
| 722 break; | |
| 723 } | |
| 724 return(rv); | |
| 725 } | |
| 726 | |
| 727 #endif /* _PR_USE_POLL */ | |
| 728 | |
| 729 static PRInt32 local_io_wait( | |
| 730 PRInt32 osfd, | |
| 731 PRInt32 wait_flag, | |
| 732 PRIntervalTime timeout) | |
| 733 { | |
| 734 _PRUnixPollDesc pd; | |
| 735 PRInt32 rv; | |
| 736 | |
| 737 PR_LOG(_pr_io_lm, PR_LOG_MIN, | |
| 738 ("waiting to %s on osfd=%d", | |
| 739 (wait_flag == _PR_UNIX_POLL_READ) ? "read" : "write", | |
| 740 osfd)); | |
| 741 | |
| 742 if (timeout == PR_INTERVAL_NO_WAIT) return 0; | |
| 743 | |
| 744 pd.osfd = osfd; | |
| 745 pd.in_flags = wait_flag; | |
| 746 pd.out_flags = 0; | |
| 747 | |
| 748 rv = _PR_WaitForMultipleFDs(&pd, 1, timeout); | |
| 749 | |
| 750 if (rv == 0) { | |
| 751 PR_SetError(PR_IO_TIMEOUT_ERROR, 0); | |
| 752 rv = -1; | |
| 753 } | |
| 754 return rv; | |
| 755 } | |
| 756 | |
| 757 | |
| 758 PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, | |
| 759 PRInt32 flags, PRIntervalTime timeout) | |
| 760 { | |
| 761 PRInt32 osfd = fd->secret->md.osfd; | |
| 762 PRInt32 rv, err; | |
| 763 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 764 | |
| 765 /* | |
| 766 * Many OS's (Solaris, Unixware) have a broken recv which won't read | |
| 767 * from socketpairs. As long as we don't use flags on socketpairs, this | |
| 768 * is a decent fix. - mikep | |
| 769 */ | |
| 770 #if defined(UNIXWARE) || defined(SOLARIS) | |
| 771 while ((rv = read(osfd,buf,amount)) == -1) { | |
| 772 #else | |
| 773 while ((rv = recv(osfd,buf,amount,flags)) == -1) { | |
| 774 #endif | |
| 775 err = _MD_ERRNO(); | |
| 776 if ((err == EAGAIN) || (err == EWOULDBLOCK)) { | |
| 777 if (fd->secret->nonblocking) { | |
| 778 break; | |
| 779 } | |
| 780 if (!_PR_IS_NATIVE_THREAD(me)) { | |
| 781 if ((rv = local_io_wait(osfd,_PR_UNIX_POLL_READ,
timeout)) < 0) | |
| 782 goto done; | |
| 783 } else { | |
| 784 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) | |
| 785 goto done; | |
| 786 } | |
| 787 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ | |
| 788 continue; | |
| 789 } else { | |
| 790 break; | |
| 791 } | |
| 792 } | |
| 793 if (rv < 0) { | |
| 794 _PR_MD_MAP_RECV_ERROR(err); | |
| 795 } | |
| 796 done: | |
| 797 return(rv); | |
| 798 } | |
| 799 | |
| 800 PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, | |
| 801 PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, | |
| 802 PRIntervalTime timeout) | |
| 803 { | |
| 804 PRInt32 osfd = fd->secret->md.osfd; | |
| 805 PRInt32 rv, err; | |
| 806 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 807 | |
| 808 while ((*addrlen = PR_NETADDR_SIZE(addr)), | |
| 809 ((rv = recvfrom(osfd, buf, amount, flags, | |
| 810 (struct sockaddr *) addr, (_PRSockLen_t *)addrlen)) == -
1)) { | |
| 811 err = _MD_ERRNO(); | |
| 812 if ((err == EAGAIN) || (err == EWOULDBLOCK)) { | |
| 813 if (fd->secret->nonblocking) { | |
| 814 break; | |
| 815 } | |
| 816 if (!_PR_IS_NATIVE_THREAD(me)) { | |
| 817 if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0) | |
| 818 goto done; | |
| 819 } else { | |
| 820 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) | |
| 821 goto done; | |
| 822 } | |
| 823 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ | |
| 824 continue; | |
| 825 } else { | |
| 826 break; | |
| 827 } | |
| 828 } | |
| 829 if (rv < 0) { | |
| 830 _PR_MD_MAP_RECVFROM_ERROR(err); | |
| 831 } | |
| 832 done: | |
| 833 #ifdef _PR_HAVE_SOCKADDR_LEN | |
| 834 if (rv != -1) { | |
| 835 /* ignore the sa_len field of struct sockaddr */ | |
| 836 if (addr) { | |
| 837 addr->raw.family = ((struct sockaddr *) addr)->sa_family; | |
| 838 } | |
| 839 } | |
| 840 #endif /* _PR_HAVE_SOCKADDR_LEN */ | |
| 841 return(rv); | |
| 842 } | |
| 843 | |
| 844 PRInt32 _MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount, | |
| 845 PRInt32 flags, PRIntervalTime timeout) | |
| 846 { | |
| 847 PRInt32 osfd = fd->secret->md.osfd; | |
| 848 PRInt32 rv, err; | |
| 849 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 850 #if defined(SOLARIS) | |
| 851 PRInt32 tmp_amount = amount; | |
| 852 #endif | |
| 853 | |
| 854 /* | |
| 855 * On pre-2.6 Solaris, send() is much slower than write(). | |
| 856 * On 2.6 and beyond, with in-kernel sockets, send() and | |
| 857 * write() are fairly equivalent in performance. | |
| 858 */ | |
| 859 #if defined(SOLARIS) | |
| 860 PR_ASSERT(0 == flags); | |
| 861 while ((rv = write(osfd,buf,tmp_amount)) == -1) { | |
| 862 #else | |
| 863 while ((rv = send(osfd,buf,amount,flags)) == -1) { | |
| 864 #endif | |
| 865 err = _MD_ERRNO(); | |
| 866 if ((err == EAGAIN) || (err == EWOULDBLOCK)) { | |
| 867 if (fd->secret->nonblocking) { | |
| 868 break; | |
| 869 } | |
| 870 if (!_PR_IS_NATIVE_THREAD(me)) { | |
| 871 if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0
) | |
| 872 goto done; | |
| 873 } else { | |
| 874 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) | |
| 875 goto done; | |
| 876 } | |
| 877 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ | |
| 878 continue; | |
| 879 } else { | |
| 880 #if defined(SOLARIS) | |
| 881 /* | |
| 882 * The write system call has been reported to return the
ERANGE | |
| 883 * error on occasion. Try to write in smaller chunks to
workaround | |
| 884 * this bug. | |
| 885 */ | |
| 886 if (err == ERANGE) { | |
| 887 if (tmp_amount > 1) { | |
| 888 tmp_amount = tmp_amount/2; /* half
the bytes */ | |
| 889 continue; | |
| 890 } | |
| 891 } | |
| 892 #endif | |
| 893 break; | |
| 894 } | |
| 895 } | |
| 896 /* | |
| 897 * optimization; if bytes sent is less than "amount" call | |
| 898 * select before returning. This is because it is likely that | |
| 899 * the next send() call will return EWOULDBLOCK. | |
| 900 */ | |
| 901 if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) | |
| 902 && (timeout != PR_INTERVAL_NO_WAIT)) { | |
| 903 if (_PR_IS_NATIVE_THREAD(me)) { | |
| 904 if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) { | |
| 905 rv = -1; | |
| 906 goto done; | |
| 907 } | |
| 908 } else { | |
| 909 if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) <
0) { | |
| 910 rv = -1; | |
| 911 goto done; | |
| 912 } | |
| 913 } | |
| 914 } | |
| 915 if (rv < 0) { | |
| 916 _PR_MD_MAP_SEND_ERROR(err); | |
| 917 } | |
| 918 done: | |
| 919 return(rv); | |
| 920 } | |
| 921 | |
| 922 PRInt32 _MD_sendto( | |
| 923 PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, | |
| 924 const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) | |
| 925 { | |
| 926 PRInt32 osfd = fd->secret->md.osfd; | |
| 927 PRInt32 rv, err; | |
| 928 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 929 #ifdef _PR_HAVE_SOCKADDR_LEN | |
| 930 PRNetAddr addrCopy; | |
| 931 | |
| 932 addrCopy = *addr; | |
| 933 ((struct sockaddr *) &addrCopy)->sa_len = addrlen; | |
| 934 ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; | |
| 935 | |
| 936 while ((rv = sendto(osfd, buf, amount, flags, | |
| 937 (struct sockaddr *) &addrCopy, addrlen)) == -1) { | |
| 938 #else | |
| 939 while ((rv = sendto(osfd, buf, amount, flags, | |
| 940 (struct sockaddr *) addr, addrlen)) == -1) { | |
| 941 #endif | |
| 942 err = _MD_ERRNO(); | |
| 943 if ((err == EAGAIN) || (err == EWOULDBLOCK)) { | |
| 944 if (fd->secret->nonblocking) { | |
| 945 break; | |
| 946 } | |
| 947 if (!_PR_IS_NATIVE_THREAD(me)) { | |
| 948 if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRIT
E, timeout)) < 0) | |
| 949 goto done; | |
| 950 } else { | |
| 951 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) | |
| 952 goto done; | |
| 953 } | |
| 954 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ | |
| 955 continue; | |
| 956 } else { | |
| 957 break; | |
| 958 } | |
| 959 } | |
| 960 if (rv < 0) { | |
| 961 _PR_MD_MAP_SENDTO_ERROR(err); | |
| 962 } | |
| 963 done: | |
| 964 return(rv); | |
| 965 } | |
| 966 | |
| 967 PRInt32 _MD_writev( | |
| 968 PRFileDesc *fd, const PRIOVec *iov, | |
| 969 PRInt32 iov_size, PRIntervalTime timeout) | |
| 970 { | |
| 971 PRInt32 rv, err; | |
| 972 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 973 PRInt32 index, amount = 0; | |
| 974 PRInt32 osfd = fd->secret->md.osfd; | |
| 975 | |
| 976 /* | |
| 977 * Calculate the total number of bytes to be sent; needed for | |
| 978 * optimization later. | |
| 979 * We could avoid this if this number was passed in; but it is | |
| 980 * probably not a big deal because iov_size is usually small (less than | |
| 981 * 3) | |
| 982 */ | |
| 983 if (!fd->secret->nonblocking) { | |
| 984 for (index=0; index<iov_size; index++) { | |
| 985 amount += iov[index].iov_len; | |
| 986 } | |
| 987 } | |
| 988 | |
| 989 while ((rv = writev(osfd, (const struct iovec*)iov, iov_size)) == -1) { | |
| 990 err = _MD_ERRNO(); | |
| 991 if ((err == EAGAIN) || (err == EWOULDBLOCK)) { | |
| 992 if (fd->secret->nonblocking) { | |
| 993 break; | |
| 994 } | |
| 995 if (!_PR_IS_NATIVE_THREAD(me)) { | |
| 996 if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRIT
E, timeout)) < 0) | |
| 997 goto done; | |
| 998 } else { | |
| 999 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0) | |
| 1000 goto done; | |
| 1001 } | |
| 1002 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ | |
| 1003 continue; | |
| 1004 } else { | |
| 1005 break; | |
| 1006 } | |
| 1007 } | |
| 1008 /* | |
| 1009 * optimization; if bytes sent is less than "amount" call | |
| 1010 * select before returning. This is because it is likely that | |
| 1011 * the next writev() call will return EWOULDBLOCK. | |
| 1012 */ | |
| 1013 if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) | |
| 1014 && (timeout != PR_INTERVAL_NO_WAIT)) { | |
| 1015 if (_PR_IS_NATIVE_THREAD(me)) { | |
| 1016 if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { | |
| 1017 rv = -1; | |
| 1018 goto done; | |
| 1019 } | |
| 1020 } else { | |
| 1021 if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) <
0) { | |
| 1022 rv = -1; | |
| 1023 goto done; | |
| 1024 } | |
| 1025 } | |
| 1026 } | |
| 1027 if (rv < 0) { | |
| 1028 _PR_MD_MAP_WRITEV_ERROR(err); | |
| 1029 } | |
| 1030 done: | |
| 1031 return(rv); | |
| 1032 } | |
| 1033 | |
| 1034 PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, | |
| 1035 PRUint32 *addrlen, PRIntervalTime timeout) | |
| 1036 { | |
| 1037 PRInt32 osfd = fd->secret->md.osfd; | |
| 1038 PRInt32 rv, err; | |
| 1039 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 1040 | |
| 1041 while ((rv = accept(osfd, (struct sockaddr *) addr, | |
| 1042 (_PRSockLen_t *)addrlen)) == -1) { | |
| 1043 err = _MD_ERRNO(); | |
| 1044 if ((err == EAGAIN) || (err == EWOULDBLOCK) || (err == ECONNABORTED)) { | |
| 1045 if (fd->secret->nonblocking) { | |
| 1046 break; | |
| 1047 } | |
| 1048 if (!_PR_IS_NATIVE_THREAD(me)) { | |
| 1049 if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ
, timeout)) < 0) | |
| 1050 goto done; | |
| 1051 } else { | |
| 1052 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) | |
| 1053 goto done; | |
| 1054 } | |
| 1055 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ | |
| 1056 continue; | |
| 1057 } else { | |
| 1058 break; | |
| 1059 } | |
| 1060 } | |
| 1061 if (rv < 0) { | |
| 1062 _PR_MD_MAP_ACCEPT_ERROR(err); | |
| 1063 } | |
| 1064 done: | |
| 1065 #ifdef _PR_HAVE_SOCKADDR_LEN | |
| 1066 if (rv != -1) { | |
| 1067 /* ignore the sa_len field of struct sockaddr */ | |
| 1068 if (addr) { | |
| 1069 addr->raw.family = ((struct sockaddr *) addr)->sa_family; | |
| 1070 } | |
| 1071 } | |
| 1072 #endif /* _PR_HAVE_SOCKADDR_LEN */ | |
| 1073 return(rv); | |
| 1074 } | |
| 1075 | |
| 1076 extern int _connect (int s, const struct sockaddr *name, int namelen); | |
| 1077 PRInt32 _MD_connect( | |
| 1078 PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime time
out) | |
| 1079 { | |
| 1080 PRInt32 rv, err; | |
| 1081 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 1082 PRInt32 osfd = fd->secret->md.osfd; | |
| 1083 #ifdef IRIX | |
| 1084 extern PRInt32 _MD_irix_connect( | |
| 1085 PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime tim
eout); | |
| 1086 #endif | |
| 1087 #ifdef _PR_HAVE_SOCKADDR_LEN | |
| 1088 PRNetAddr addrCopy; | |
| 1089 | |
| 1090 addrCopy = *addr; | |
| 1091 ((struct sockaddr *) &addrCopy)->sa_len = addrlen; | |
| 1092 ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; | |
| 1093 #endif | |
| 1094 | |
| 1095 /* | |
| 1096 * We initiate the connection setup by making a nonblocking connect() | |
| 1097 * call. If the connect() call fails, there are two cases we handle | |
| 1098 * specially: | |
| 1099 * 1. The connect() call was interrupted by a signal. In this case | |
| 1100 * we simply retry connect(). | |
| 1101 * 2. The NSPR socket is nonblocking and connect() fails with | |
| 1102 * EINPROGRESS. We first wait until the socket becomes writable. | |
| 1103 * Then we try to find out whether the connection setup succeeded | |
| 1104 * or failed. | |
| 1105 */ | |
| 1106 | |
| 1107 retry: | |
| 1108 #ifdef IRIX | |
| 1109 if ((rv = _MD_irix_connect(osfd, addr, addrlen, timeout)) == -1) { | |
| 1110 #else | |
| 1111 #ifdef _PR_HAVE_SOCKADDR_LEN | |
| 1112 if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) { | |
| 1113 #else | |
| 1114 if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) { | |
| 1115 #endif | |
| 1116 #endif | |
| 1117 err = _MD_ERRNO(); | |
| 1118 | |
| 1119 if (err == EINTR) { | |
| 1120 if (_PR_PENDING_INTERRUPT(me)) { | |
| 1121 me->flags &= ~_PR_INTERRUPT; | |
| 1122 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); | |
| 1123 return -1; | |
| 1124 } | |
| 1125 goto retry; | |
| 1126 } | |
| 1127 | |
| 1128 if (!fd->secret->nonblocking && (err == EINPROGRESS)) { | |
| 1129 if (!_PR_IS_NATIVE_THREAD(me)) { | |
| 1130 | |
| 1131 if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRIT
E, timeout)) < 0) | |
| 1132 return -1; | |
| 1133 } else { | |
| 1134 /* | |
| 1135 * socket_io_wait() may return -1 or 1. | |
| 1136 */ | |
| 1137 | |
| 1138 rv = socket_io_wait(osfd, WRITE_FD, timeout); | |
| 1139 if (rv == -1) { | |
| 1140 return -1; | |
| 1141 } | |
| 1142 } | |
| 1143 | |
| 1144 PR_ASSERT(rv == 1); | |
| 1145 if (_PR_PENDING_INTERRUPT(me)) { | |
| 1146 me->flags &= ~_PR_INTERRUPT; | |
| 1147 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); | |
| 1148 return -1; | |
| 1149 } | |
| 1150 err = _MD_unix_get_nonblocking_connect_error(osfd); | |
| 1151 if (err != 0) { | |
| 1152 _PR_MD_MAP_CONNECT_ERROR(err); | |
| 1153 return -1; | |
| 1154 } | |
| 1155 return 0; | |
| 1156 } | |
| 1157 | |
| 1158 _PR_MD_MAP_CONNECT_ERROR(err); | |
| 1159 } | |
| 1160 | |
| 1161 return rv; | |
| 1162 } /* _MD_connect */ | |
| 1163 | |
| 1164 PRInt32 _MD_bind(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) | |
| 1165 { | |
| 1166 PRInt32 rv, err; | |
| 1167 #ifdef _PR_HAVE_SOCKADDR_LEN | |
| 1168 PRNetAddr addrCopy; | |
| 1169 | |
| 1170 addrCopy = *addr; | |
| 1171 ((struct sockaddr *) &addrCopy)->sa_len = addrlen; | |
| 1172 ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; | |
| 1173 rv = bind(fd->secret->md.osfd, (struct sockaddr *) &addrCopy, (int )addrlen)
; | |
| 1174 #else | |
| 1175 rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen); | |
| 1176 #endif | |
| 1177 if (rv < 0) { | |
| 1178 err = _MD_ERRNO(); | |
| 1179 _PR_MD_MAP_BIND_ERROR(err); | |
| 1180 } | |
| 1181 return(rv); | |
| 1182 } | |
| 1183 | |
| 1184 PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog) | |
| 1185 { | |
| 1186 PRInt32 rv, err; | |
| 1187 | |
| 1188 rv = listen(fd->secret->md.osfd, backlog); | |
| 1189 if (rv < 0) { | |
| 1190 err = _MD_ERRNO(); | |
| 1191 _PR_MD_MAP_LISTEN_ERROR(err); | |
| 1192 } | |
| 1193 return(rv); | |
| 1194 } | |
| 1195 | |
| 1196 PRInt32 _MD_shutdown(PRFileDesc *fd, PRIntn how) | |
| 1197 { | |
| 1198 PRInt32 rv, err; | |
| 1199 | |
| 1200 rv = shutdown(fd->secret->md.osfd, how); | |
| 1201 if (rv < 0) { | |
| 1202 err = _MD_ERRNO(); | |
| 1203 _PR_MD_MAP_SHUTDOWN_ERROR(err); | |
| 1204 } | |
| 1205 return(rv); | |
| 1206 } | |
| 1207 | |
| 1208 PRInt32 _MD_socketpair(int af, int type, int flags, | |
| 1209 PRInt32 *osfd) | |
| 1210 { | |
| 1211 PRInt32 rv, err; | |
| 1212 | |
| 1213 rv = socketpair(af, type, flags, osfd); | |
| 1214 if (rv < 0) { | |
| 1215 err = _MD_ERRNO(); | |
| 1216 _PR_MD_MAP_SOCKETPAIR_ERROR(err); | |
| 1217 } | |
| 1218 return rv; | |
| 1219 } | |
| 1220 | |
| 1221 PRStatus _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, | |
| 1222 PRUint32 *addrlen) | |
| 1223 { | |
| 1224 PRInt32 rv, err; | |
| 1225 | |
| 1226 rv = getsockname(fd->secret->md.osfd, | |
| 1227 (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); | |
| 1228 #ifdef _PR_HAVE_SOCKADDR_LEN | |
| 1229 if (rv == 0) { | |
| 1230 /* ignore the sa_len field of struct sockaddr */ | |
| 1231 if (addr) { | |
| 1232 addr->raw.family = ((struct sockaddr *) addr)->sa_family; | |
| 1233 } | |
| 1234 } | |
| 1235 #endif /* _PR_HAVE_SOCKADDR_LEN */ | |
| 1236 if (rv < 0) { | |
| 1237 err = _MD_ERRNO(); | |
| 1238 _PR_MD_MAP_GETSOCKNAME_ERROR(err); | |
| 1239 } | |
| 1240 return rv==0?PR_SUCCESS:PR_FAILURE; | |
| 1241 } | |
| 1242 | |
| 1243 PRStatus _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, | |
| 1244 PRUint32 *addrlen) | |
| 1245 { | |
| 1246 PRInt32 rv, err; | |
| 1247 | |
| 1248 rv = getpeername(fd->secret->md.osfd, | |
| 1249 (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); | |
| 1250 #ifdef _PR_HAVE_SOCKADDR_LEN | |
| 1251 if (rv == 0) { | |
| 1252 /* ignore the sa_len field of struct sockaddr */ | |
| 1253 if (addr) { | |
| 1254 addr->raw.family = ((struct sockaddr *) addr)->sa_family; | |
| 1255 } | |
| 1256 } | |
| 1257 #endif /* _PR_HAVE_SOCKADDR_LEN */ | |
| 1258 if (rv < 0) { | |
| 1259 err = _MD_ERRNO(); | |
| 1260 _PR_MD_MAP_GETPEERNAME_ERROR(err); | |
| 1261 } | |
| 1262 return rv==0?PR_SUCCESS:PR_FAILURE; | |
| 1263 } | |
| 1264 | |
| 1265 PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, | |
| 1266 PRInt32 optname, char* optval, PRInt32* optlen) | |
| 1267 { | |
| 1268 PRInt32 rv, err; | |
| 1269 | |
| 1270 rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (_PRSockLen_t *
)optlen); | |
| 1271 if (rv < 0) { | |
| 1272 err = _MD_ERRNO(); | |
| 1273 _PR_MD_MAP_GETSOCKOPT_ERROR(err); | |
| 1274 } | |
| 1275 return rv==0?PR_SUCCESS:PR_FAILURE; | |
| 1276 } | |
| 1277 | |
| 1278 PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, | |
| 1279 PRInt32 optname, const char* optval, PRInt32 optlen) | |
| 1280 { | |
| 1281 PRInt32 rv, err; | |
| 1282 | |
| 1283 rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen); | |
| 1284 if (rv < 0) { | |
| 1285 err = _MD_ERRNO(); | |
| 1286 _PR_MD_MAP_SETSOCKOPT_ERROR(err); | |
| 1287 } | |
| 1288 return rv==0?PR_SUCCESS:PR_FAILURE; | |
| 1289 } | |
| 1290 | |
| 1291 PRStatus _MD_set_fd_inheritable(PRFileDesc *fd, PRBool inheritable) | |
| 1292 { | |
| 1293 int rv; | |
| 1294 | |
| 1295 rv = fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC); | |
| 1296 if (-1 == rv) { | |
| 1297 PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); | |
| 1298 return PR_FAILURE; | |
| 1299 } | |
| 1300 return PR_SUCCESS; | |
| 1301 } | |
| 1302 | |
| 1303 void _MD_init_fd_inheritable(PRFileDesc *fd, PRBool imported) | |
| 1304 { | |
| 1305 if (imported) { | |
| 1306 fd->secret->inheritable = _PR_TRI_UNKNOWN; | |
| 1307 } else { | |
| 1308 /* By default, a Unix fd is not closed on exec. */ | |
| 1309 #ifdef DEBUG | |
| 1310 { | |
| 1311 int flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); | |
| 1312 PR_ASSERT(0 == flags); | |
| 1313 } | |
| 1314 #endif | |
| 1315 fd->secret->inheritable = _PR_TRI_TRUE; | |
| 1316 } | |
| 1317 } | |
| 1318 | |
| 1319 /************************************************************************/ | |
| 1320 #if !defined(_PR_USE_POLL) | |
| 1321 | |
| 1322 /* | |
| 1323 ** Scan through io queue and find any bad fd's that triggered the error | |
| 1324 ** from _MD_SELECT | |
| 1325 */ | |
| 1326 static void FindBadFDs(void) | |
| 1327 { | |
| 1328 PRCList *q; | |
| 1329 PRThread *me = _MD_CURRENT_THREAD(); | |
| 1330 | |
| 1331 PR_ASSERT(!_PR_IS_NATIVE_THREAD(me)); | |
| 1332 q = (_PR_IOQ(me->cpu)).next; | |
| 1333 _PR_IOQ_MAX_OSFD(me->cpu) = -1; | |
| 1334 _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; | |
| 1335 while (q != &_PR_IOQ(me->cpu)) { | |
| 1336 PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); | |
| 1337 PRBool notify = PR_FALSE; | |
| 1338 _PRUnixPollDesc *pds = pq->pds; | |
| 1339 _PRUnixPollDesc *epds = pds + pq->npds; | |
| 1340 PRInt32 pq_max_osfd = -1; | |
| 1341 | |
| 1342 q = q->next; | |
| 1343 for (; pds < epds; pds++) { | |
| 1344 PRInt32 osfd = pds->osfd; | |
| 1345 pds->out_flags = 0; | |
| 1346 PR_ASSERT(osfd >= 0 || pds->in_flags == 0); | |
| 1347 if (pds->in_flags == 0) { | |
| 1348 continue; /* skip this fd */ | |
| 1349 } | |
| 1350 if (fcntl(osfd, F_GETFL, 0) == -1) { | |
| 1351 /* Found a bad descriptor, remove it from the fd_sets. */ | |
| 1352 PR_LOG(_pr_io_lm, PR_LOG_MAX, | |
| 1353 ("file descriptor %d is bad", osfd)); | |
| 1354 pds->out_flags = _PR_UNIX_POLL_NVAL; | |
| 1355 notify = PR_TRUE; | |
| 1356 } | |
| 1357 if (osfd > pq_max_osfd) { | |
| 1358 pq_max_osfd = osfd; | |
| 1359 } | |
| 1360 } | |
| 1361 | |
| 1362 if (notify) { | |
| 1363 PRIntn pri; | |
| 1364 PR_REMOVE_LINK(&pq->links); | |
| 1365 pq->on_ioq = PR_FALSE; | |
| 1366 | |
| 1367 /* | |
| 1368 * Decrement the count of descriptors for each desciptor/event | |
| 1369 * because this I/O request is being removed from the | |
| 1370 * ioq | |
| 1371 */ | |
| 1372 pds = pq->pds; | |
| 1373 for (; pds < epds; pds++) { | |
| 1374 PRInt32 osfd = pds->osfd; | |
| 1375 PRInt16 in_flags = pds->in_flags; | |
| 1376 PR_ASSERT(osfd >= 0 || in_flags == 0); | |
| 1377 if (in_flags & _PR_UNIX_POLL_READ) { | |
| 1378 if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) | |
| 1379 FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); | |
| 1380 } | |
| 1381 if (in_flags & _PR_UNIX_POLL_WRITE) { | |
| 1382 if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) | |
| 1383 FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); | |
| 1384 } | |
| 1385 if (in_flags & _PR_UNIX_POLL_EXCEPT) { | |
| 1386 if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) | |
| 1387 FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); | |
| 1388 } | |
| 1389 } | |
| 1390 | |
| 1391 _PR_THREAD_LOCK(pq->thr); | |
| 1392 if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { | |
| 1393 _PRCPU *cpu = pq->thr->cpu; | |
| 1394 _PR_SLEEPQ_LOCK(pq->thr->cpu); | |
| 1395 _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); | |
| 1396 _PR_SLEEPQ_UNLOCK(pq->thr->cpu); | |
| 1397 | |
| 1398 if (pq->thr->flags & _PR_SUSPENDING) { | |
| 1399 /* | |
| 1400 * set thread state to SUSPENDED; | |
| 1401 * a Resume operation on the thread | |
| 1402 * will move it to the runQ | |
| 1403 */ | |
| 1404 pq->thr->state = _PR_SUSPENDED; | |
| 1405 _PR_MISCQ_LOCK(pq->thr->cpu); | |
| 1406 _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu); | |
| 1407 _PR_MISCQ_UNLOCK(pq->thr->cpu); | |
| 1408 } else { | |
| 1409 pri = pq->thr->priority; | |
| 1410 pq->thr->state = _PR_RUNNABLE; | |
| 1411 | |
| 1412 _PR_RUNQ_LOCK(cpu); | |
| 1413 _PR_ADD_RUNQ(pq->thr, cpu, pri); | |
| 1414 _PR_RUNQ_UNLOCK(cpu); | |
| 1415 } | |
| 1416 } | |
| 1417 _PR_THREAD_UNLOCK(pq->thr); | |
| 1418 } else { | |
| 1419 if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) | |
| 1420 _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; | |
| 1421 if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) | |
| 1422 _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; | |
| 1423 } | |
| 1424 } | |
| 1425 if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { | |
| 1426 if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) | |
| 1427 _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; | |
| 1428 } | |
| 1429 } | |
| 1430 #endif /* !defined(_PR_USE_POLL) */ | |
| 1431 | |
| 1432 /************************************************************************/ | |
| 1433 | |
| 1434 /* | |
| 1435 ** Called by the scheduler when there is nothing to do. This means that | |
| 1436 ** all threads are blocked on some monitor somewhere. | |
| 1437 ** | |
| 1438 ** Note: this code doesn't release the scheduler lock. | |
| 1439 */ | |
| 1440 /* | |
| 1441 ** Pause the current CPU. longjmp to the cpu's pause stack | |
| 1442 ** | |
| 1443 ** This must be called with the scheduler locked | |
| 1444 */ | |
| 1445 void _MD_PauseCPU(PRIntervalTime ticks) | |
| 1446 { | |
| 1447 PRThread *me = _MD_CURRENT_THREAD(); | |
| 1448 #ifdef _PR_USE_POLL | |
| 1449 int timeout; | |
| 1450 struct pollfd *pollfds; /* an array of pollfd structures */ | |
| 1451 struct pollfd *pollfdPtr; /* a pointer that steps through the array */ | |
| 1452 unsigned long npollfds; /* number of pollfd structures in array */ | |
| 1453 unsigned long pollfds_size; | |
| 1454 int nfd; /* to hold the return value of poll() */ | |
| 1455 #else | |
| 1456 struct timeval timeout, *tvp; | |
| 1457 fd_set r, w, e; | |
| 1458 fd_set *rp, *wp, *ep; | |
| 1459 PRInt32 max_osfd, nfd; | |
| 1460 #endif /* _PR_USE_POLL */ | |
| 1461 PRInt32 rv; | |
| 1462 PRCList *q; | |
| 1463 PRUint32 min_timeout; | |
| 1464 sigset_t oldset; | |
| 1465 #ifdef IRIX | |
| 1466 extern sigset_t ints_off; | |
| 1467 #endif | |
| 1468 | |
| 1469 PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); | |
| 1470 | |
| 1471 _PR_MD_IOQ_LOCK(); | |
| 1472 | |
| 1473 #ifdef _PR_USE_POLL | |
| 1474 /* Build up the pollfd structure array to wait on */ | |
| 1475 | |
| 1476 /* Find out how many pollfd structures are needed */ | |
| 1477 npollfds = _PR_IOQ_OSFD_CNT(me->cpu); | |
| 1478 PR_ASSERT(npollfds >= 0); | |
| 1479 | |
| 1480 /* | |
| 1481 * We use a pipe to wake up a native thread. An fd is needed | |
| 1482 * for the pipe and we poll it for reading. | |
| 1483 */ | |
| 1484 if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { | |
| 1485 npollfds++; | |
| 1486 #ifdef IRIX | |
| 1487 /* | |
| 1488 * On Irix, a second pipe is used to cause the primordial cpu to | |
| 1489 * wakeup and exit, when the process is exiting because of a cal
l | |
| 1490 * to exit/PR_ProcessExit. | |
| 1491 */ | |
| 1492 if (me->cpu->id == 0) { | |
| 1493 npollfds++; | |
| 1494 } | |
| 1495 #endif | |
| 1496 } | |
| 1497 | |
| 1498 /* | |
| 1499 * if the cpu's pollfd array is not big enough, release it and allocate a ne
w one | |
| 1500 */ | |
| 1501 if (npollfds > _PR_IOQ_POLLFDS_SIZE(me->cpu)) { | |
| 1502 if (_PR_IOQ_POLLFDS(me->cpu) != NULL) | |
| 1503 PR_DELETE(_PR_IOQ_POLLFDS(me->cpu)); | |
| 1504 pollfds_size = PR_MAX(_PR_IOQ_MIN_POLLFDS_SIZE(me->cpu), npollfds); | |
| 1505 pollfds = (struct pollfd *) PR_MALLOC(pollfds_size * sizeof(struct pollf
d)); | |
| 1506 _PR_IOQ_POLLFDS(me->cpu) = pollfds; | |
| 1507 _PR_IOQ_POLLFDS_SIZE(me->cpu) = pollfds_size; | |
| 1508 } else { | |
| 1509 pollfds = _PR_IOQ_POLLFDS(me->cpu); | |
| 1510 } | |
| 1511 pollfdPtr = pollfds; | |
| 1512 | |
| 1513 /* | |
| 1514 * If we need to poll the pipe for waking up a native thread, | |
| 1515 * the pipe's fd is the first element in the pollfds array. | |
| 1516 */ | |
| 1517 if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { | |
| 1518 pollfdPtr->fd = _pr_md_pipefd[0]; | |
| 1519 pollfdPtr->events = POLLIN; | |
| 1520 pollfdPtr++; | |
| 1521 #ifdef IRIX | |
| 1522 /* | |
| 1523 * On Irix, the second element is the exit pipe | |
| 1524 */ | |
| 1525 if (me->cpu->id == 0) { | |
| 1526 pollfdPtr->fd = _pr_irix_primoridal_cpu_fd[0]; | |
| 1527 pollfdPtr->events = POLLIN; | |
| 1528 pollfdPtr++; | |
| 1529 } | |
| 1530 #endif | |
| 1531 } | |
| 1532 | |
| 1533 min_timeout = PR_INTERVAL_NO_TIMEOUT; | |
| 1534 for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) { | |
| 1535 PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); | |
| 1536 _PRUnixPollDesc *pds = pq->pds; | |
| 1537 _PRUnixPollDesc *epds = pds + pq->npds; | |
| 1538 | |
| 1539 if (pq->timeout < min_timeout) { | |
| 1540 min_timeout = pq->timeout; | |
| 1541 } | |
| 1542 for (; pds < epds; pds++, pollfdPtr++) { | |
| 1543 /* | |
| 1544 * Assert that the pollfdPtr pointer does not go | |
| 1545 * beyond the end of the pollfds array | |
| 1546 */ | |
| 1547 PR_ASSERT(pollfdPtr < pollfds + npollfds); | |
| 1548 pollfdPtr->fd = pds->osfd; | |
| 1549 /* direct copy of poll flags */ | |
| 1550 pollfdPtr->events = pds->in_flags; | |
| 1551 } | |
| 1552 } | |
| 1553 _PR_IOQ_TIMEOUT(me->cpu) = min_timeout; | |
| 1554 #else | |
| 1555 /* | |
| 1556 * assigment of fd_sets | |
| 1557 */ | |
| 1558 r = _PR_FD_READ_SET(me->cpu); | |
| 1559 w = _PR_FD_WRITE_SET(me->cpu); | |
| 1560 e = _PR_FD_EXCEPTION_SET(me->cpu); | |
| 1561 | |
| 1562 rp = &r; | |
| 1563 wp = &w; | |
| 1564 ep = &e; | |
| 1565 | |
| 1566 max_osfd = _PR_IOQ_MAX_OSFD(me->cpu) + 1; | |
| 1567 min_timeout = _PR_IOQ_TIMEOUT(me->cpu); | |
| 1568 #endif /* _PR_USE_POLL */ | |
| 1569 /* | |
| 1570 ** Compute the minimum timeout value: make it the smaller of the | |
| 1571 ** timeouts specified by the i/o pollers or the timeout of the first | |
| 1572 ** sleeping thread. | |
| 1573 */ | |
| 1574 q = _PR_SLEEPQ(me->cpu).next; | |
| 1575 | |
| 1576 if (q != &_PR_SLEEPQ(me->cpu)) { | |
| 1577 PRThread *t = _PR_THREAD_PTR(q); | |
| 1578 | |
| 1579 if (t->sleep < min_timeout) { | |
| 1580 min_timeout = t->sleep; | |
| 1581 } | |
| 1582 } | |
| 1583 if (min_timeout > ticks) { | |
| 1584 min_timeout = ticks; | |
| 1585 } | |
| 1586 | |
| 1587 #ifdef _PR_USE_POLL | |
| 1588 if (min_timeout == PR_INTERVAL_NO_TIMEOUT) | |
| 1589 timeout = -1; | |
| 1590 else | |
| 1591 timeout = PR_IntervalToMilliseconds(min_timeout); | |
| 1592 #else | |
| 1593 if (min_timeout == PR_INTERVAL_NO_TIMEOUT) { | |
| 1594 tvp = NULL; | |
| 1595 } else { | |
| 1596 timeout.tv_sec = PR_IntervalToSeconds(min_timeout); | |
| 1597 timeout.tv_usec = PR_IntervalToMicroseconds(min_timeout) | |
| 1598 % PR_USEC_PER_SEC; | |
| 1599 tvp = &timeout; | |
| 1600 } | |
| 1601 #endif /* _PR_USE_POLL */ | |
| 1602 | |
| 1603 _PR_MD_IOQ_UNLOCK(); | |
| 1604 _MD_CHECK_FOR_EXIT(); | |
| 1605 /* | |
| 1606 * check for i/o operations | |
| 1607 */ | |
| 1608 #ifndef _PR_NO_CLOCK_TIMER | |
| 1609 /* | |
| 1610 * Disable the clock interrupts while we are in select, if clock interrupts | |
| 1611 * are enabled. Otherwise, when the select/poll calls are interrupted, the | |
| 1612 * timer value starts ticking from zero again when the system call is restar
ted. | |
| 1613 */ | |
| 1614 #ifdef IRIX | |
| 1615 /* | |
| 1616 * SIGCHLD signal is used on Irix to detect he termination of an | |
| 1617 * sproc by SIGSEGV, SIGBUS or SIGABRT signals when | |
| 1618 * _nspr_terminate_on_error is set. | |
| 1619 */ | |
| 1620 if ((!_nspr_noclock) || (_nspr_terminate_on_error)) | |
| 1621 #else | |
| 1622 if (!_nspr_noclock) | |
| 1623 #endif /* IRIX */ | |
| 1624 #ifdef IRIX | |
| 1625 sigprocmask(SIG_BLOCK, &ints_off, &oldset); | |
| 1626 #else | |
| 1627 PR_ASSERT(sigismember(&timer_set, SIGALRM)); | |
| 1628 sigprocmask(SIG_BLOCK, &timer_set, &oldset); | |
| 1629 #endif /* IRIX */ | |
| 1630 #endif /* !_PR_NO_CLOCK_TIMER */ | |
| 1631 | |
| 1632 #ifndef _PR_USE_POLL | |
| 1633 PR_ASSERT(FD_ISSET(_pr_md_pipefd[0],rp)); | |
| 1634 nfd = _MD_SELECT(max_osfd, rp, wp, ep, tvp); | |
| 1635 #else | |
| 1636 nfd = _MD_POLL(pollfds, npollfds, timeout); | |
| 1637 #endif /* !_PR_USE_POLL */ | |
| 1638 | |
| 1639 #ifndef _PR_NO_CLOCK_TIMER | |
| 1640 #ifdef IRIX | |
| 1641 if ((!_nspr_noclock) || (_nspr_terminate_on_error)) | |
| 1642 #else | |
| 1643 if (!_nspr_noclock) | |
| 1644 #endif /* IRIX */ | |
| 1645 sigprocmask(SIG_SETMASK, &oldset, 0); | |
| 1646 #endif /* !_PR_NO_CLOCK_TIMER */ | |
| 1647 | |
| 1648 _MD_CHECK_FOR_EXIT(); | |
| 1649 | |
| 1650 #ifdef IRIX | |
| 1651 _PR_MD_primordial_cpu(); | |
| 1652 #endif | |
| 1653 | |
| 1654 _PR_MD_IOQ_LOCK(); | |
| 1655 /* | |
| 1656 ** Notify monitors that are associated with the selected descriptors. | |
| 1657 */ | |
| 1658 #ifdef _PR_USE_POLL | |
| 1659 if (nfd > 0) { | |
| 1660 pollfdPtr = pollfds; | |
| 1661 if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { | |
| 1662 /* | |
| 1663 * Assert that the pipe is the first element in the | |
| 1664 * pollfds array. | |
| 1665 */ | |
| 1666 PR_ASSERT(pollfds[0].fd == _pr_md_pipefd[0]); | |
| 1667 if ((pollfds[0].revents & POLLIN) && (nfd == 1)) { | |
| 1668 /* | |
| 1669 * woken up by another thread; read all the data | |
| 1670 * in the pipe to empty the pipe | |
| 1671 */ | |
| 1672 while ((rv = read(_pr_md_pipefd[0], _pr_md_pipebuf, | |
| 1673 PIPE_BUF)) == PIPE_BUF){ | |
| 1674 } | |
| 1675 PR_ASSERT((rv > 0) || ((rv == -1) && (errno == EAGAIN))); | |
| 1676 } | |
| 1677 pollfdPtr++; | |
| 1678 #ifdef IRIX | |
| 1679 /* | |
| 1680 * On Irix, check to see if the primordial cpu needs to
exit | |
| 1681 * to cause the process to terminate | |
| 1682 */ | |
| 1683 if (me->cpu->id == 0) { | |
| 1684 PR_ASSERT(pollfds[1].fd == _pr_irix_primoridal_cpu_fd[0]); | |
| 1685 if (pollfdPtr->revents & POLLIN) { | |
| 1686 if (_pr_irix_process_exit) { | |
| 1687 /* | |
| 1688 * process exit due to a call to
PR_ProcessExit | |
| 1689 */ | |
| 1690 prctl(PR_SETEXITSIG, SIGKILL); | |
| 1691 _exit(_pr_irix_process_exit_code
); | |
| 1692 } else { | |
| 1693 while ((rv = read(_pr_irix_primo
ridal_cpu_fd[0], | |
| 1694 _pr_md_pipebuf, PIPE_BUF
)) == PIPE_BUF) { | |
| 1695 } | |
| 1696 PR_ASSERT(rv > 0); | |
| 1697 } | |
| 1698 } | |
| 1699 pollfdPtr++; | |
| 1700 } | |
| 1701 #endif | |
| 1702 } | |
| 1703 for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) { | |
| 1704 PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); | |
| 1705 PRBool notify = PR_FALSE; | |
| 1706 _PRUnixPollDesc *pds = pq->pds; | |
| 1707 _PRUnixPollDesc *epds = pds + pq->npds; | |
| 1708 | |
| 1709 for (; pds < epds; pds++, pollfdPtr++) { | |
| 1710 /* | |
| 1711 * Assert that the pollfdPtr pointer does not go beyond | |
| 1712 * the end of the pollfds array. | |
| 1713 */ | |
| 1714 PR_ASSERT(pollfdPtr < pollfds + npollfds); | |
| 1715 /* | |
| 1716 * Assert that the fd's in the pollfds array (stepped | |
| 1717 * through by pollfdPtr) are in the same order as | |
| 1718 * the fd's in _PR_IOQ() (stepped through by q and pds). | |
| 1719 * This is how the pollfds array was created earlier. | |
| 1720 */ | |
| 1721 PR_ASSERT(pollfdPtr->fd == pds->osfd); | |
| 1722 pds->out_flags = pollfdPtr->revents; | |
| 1723 /* Negative fd's are ignored by poll() */ | |
| 1724 if (pds->osfd >= 0 && pds->out_flags) { | |
| 1725 notify = PR_TRUE; | |
| 1726 } | |
| 1727 } | |
| 1728 if (notify) { | |
| 1729 PRIntn pri; | |
| 1730 PRThread *thred; | |
| 1731 | |
| 1732 PR_REMOVE_LINK(&pq->links); | |
| 1733 pq->on_ioq = PR_FALSE; | |
| 1734 | |
| 1735 thred = pq->thr; | |
| 1736 _PR_THREAD_LOCK(thred); | |
| 1737 if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { | |
| 1738 _PRCPU *cpu = pq->thr->cpu; | |
| 1739 _PR_SLEEPQ_LOCK(pq->thr->cpu); | |
| 1740 _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); | |
| 1741 _PR_SLEEPQ_UNLOCK(pq->thr->cpu); | |
| 1742 | |
| 1743 if (pq->thr->flags & _PR_SUSPENDING) { | |
| 1744 /* | |
| 1745 * set thread state to SUSPENDED; | |
| 1746 * a Resume operation on the thread | |
| 1747 * will move it to the runQ | |
| 1748 */ | |
| 1749 pq->thr->state = _PR_SUSPENDED; | |
| 1750 _PR_MISCQ_LOCK(pq->thr->cpu); | |
| 1751 _PR_ADD_SUSPENDQ(pq->thr, pq->thr->c
pu); | |
| 1752 _PR_MISCQ_UNLOCK(pq->thr->cpu); | |
| 1753 } else { | |
| 1754 pri = pq->thr->priority; | |
| 1755 pq->thr->state = _PR_RUNNABLE; | |
| 1756 | |
| 1757 _PR_RUNQ_LOCK(cpu); | |
| 1758 _PR_ADD_RUNQ(pq->thr, cpu, pri); | |
| 1759 _PR_RUNQ_UNLOCK(cpu); | |
| 1760 if (_pr_md_idle_cpus > 1) | |
| 1761 _PR_MD_WAKEUP_WAITER(thr
ed); | |
| 1762 } | |
| 1763 } | |
| 1764 _PR_THREAD_UNLOCK(thred); | |
| 1765 _PR_IOQ_OSFD_CNT(me->cpu) -= pq->npds; | |
| 1766 PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0); | |
| 1767 } | |
| 1768 } | |
| 1769 } else if (nfd == -1) { | |
| 1770 PR_LOG(_pr_io_lm, PR_LOG_MAX, ("poll() failed with errno %d", errno)); | |
| 1771 } | |
| 1772 | |
| 1773 #else | |
| 1774 if (nfd > 0) { | |
| 1775 q = _PR_IOQ(me->cpu).next; | |
| 1776 _PR_IOQ_MAX_OSFD(me->cpu) = -1; | |
| 1777 _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; | |
| 1778 while (q != &_PR_IOQ(me->cpu)) { | |
| 1779 PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); | |
| 1780 PRBool notify = PR_FALSE; | |
| 1781 _PRUnixPollDesc *pds = pq->pds; | |
| 1782 _PRUnixPollDesc *epds = pds + pq->npds; | |
| 1783 PRInt32 pq_max_osfd = -1; | |
| 1784 | |
| 1785 q = q->next; | |
| 1786 for (; pds < epds; pds++) { | |
| 1787 PRInt32 osfd = pds->osfd; | |
| 1788 PRInt16 in_flags = pds->in_flags; | |
| 1789 PRInt16 out_flags = 0; | |
| 1790 PR_ASSERT(osfd >= 0 || in_flags == 0); | |
| 1791 if ((in_flags & _PR_UNIX_POLL_READ) && FD_ISSET(osfd, rp)) { | |
| 1792 out_flags |= _PR_UNIX_POLL_READ; | |
| 1793 } | |
| 1794 if ((in_flags & _PR_UNIX_POLL_WRITE) && FD_ISSET(osfd, wp)) { | |
| 1795 out_flags |= _PR_UNIX_POLL_WRITE; | |
| 1796 } | |
| 1797 if ((in_flags & _PR_UNIX_POLL_EXCEPT) && FD_ISSET(osfd, ep)) { | |
| 1798 out_flags |= _PR_UNIX_POLL_EXCEPT; | |
| 1799 } | |
| 1800 pds->out_flags = out_flags; | |
| 1801 if (out_flags) { | |
| 1802 notify = PR_TRUE; | |
| 1803 } | |
| 1804 if (osfd > pq_max_osfd) { | |
| 1805 pq_max_osfd = osfd; | |
| 1806 } | |
| 1807 } | |
| 1808 if (notify == PR_TRUE) { | |
| 1809 PRIntn pri; | |
| 1810 PRThread *thred; | |
| 1811 | |
| 1812 PR_REMOVE_LINK(&pq->links); | |
| 1813 pq->on_ioq = PR_FALSE; | |
| 1814 | |
| 1815 /* | |
| 1816 * Decrement the count of descriptors for each desciptor/event | |
| 1817 * because this I/O request is being removed from the | |
| 1818 * ioq | |
| 1819 */ | |
| 1820 pds = pq->pds; | |
| 1821 for (; pds < epds; pds++) { | |
| 1822 PRInt32 osfd = pds->osfd; | |
| 1823 PRInt16 in_flags = pds->in_flags; | |
| 1824 PR_ASSERT(osfd >= 0 || in_flags == 0); | |
| 1825 if (in_flags & _PR_UNIX_POLL_READ) { | |
| 1826 if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) | |
| 1827 FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); | |
| 1828 } | |
| 1829 if (in_flags & _PR_UNIX_POLL_WRITE) { | |
| 1830 if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) | |
| 1831 FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); | |
| 1832 } | |
| 1833 if (in_flags & _PR_UNIX_POLL_EXCEPT) { | |
| 1834 if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) | |
| 1835 FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); | |
| 1836 } | |
| 1837 } | |
| 1838 | |
| 1839 /* | |
| 1840 * Because this thread can run on a different cpu right | |
| 1841 * after being added to the run queue, do not dereference | |
| 1842 * pq | |
| 1843 */ | |
| 1844 thred = pq->thr; | |
| 1845 _PR_THREAD_LOCK(thred); | |
| 1846 if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { | |
| 1847 _PRCPU *cpu = thred->cpu; | |
| 1848 _PR_SLEEPQ_LOCK(pq->thr->cpu); | |
| 1849 _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); | |
| 1850 _PR_SLEEPQ_UNLOCK(pq->thr->cpu); | |
| 1851 | |
| 1852 if (pq->thr->flags & _PR_SUSPENDING) { | |
| 1853 /* | |
| 1854 * set thread state to SUSPENDED; | |
| 1855 * a Resume operation on the thread | |
| 1856 * will move it to the runQ | |
| 1857 */ | |
| 1858 pq->thr->state = _PR_SUSPENDED; | |
| 1859 _PR_MISCQ_LOCK(pq->thr->cpu); | |
| 1860 _PR_ADD_SUSPENDQ(pq->thr, pq->thr->c
pu); | |
| 1861 _PR_MISCQ_UNLOCK(pq->thr->cpu); | |
| 1862 } else { | |
| 1863 pri = pq->thr->priority; | |
| 1864 pq->thr->state = _PR_RUNNABLE; | |
| 1865 | |
| 1866 pq->thr->cpu = cpu; | |
| 1867 _PR_RUNQ_LOCK(cpu); | |
| 1868 _PR_ADD_RUNQ(pq->thr, cpu, pri); | |
| 1869 _PR_RUNQ_UNLOCK(cpu); | |
| 1870 if (_pr_md_idle_cpus > 1) | |
| 1871 _PR_MD_WAKEUP_WAITER(thr
ed); | |
| 1872 } | |
| 1873 } | |
| 1874 _PR_THREAD_UNLOCK(thred); | |
| 1875 } else { | |
| 1876 if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) | |
| 1877 _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; | |
| 1878 if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) | |
| 1879 _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; | |
| 1880 } | |
| 1881 } | |
| 1882 if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { | |
| 1883 if ((FD_ISSET(_pr_md_pipefd[0], rp)) && (nfd == 1)) { | |
| 1884 /* | |
| 1885 * woken up by another thread; read all the data | |
| 1886 * in the pipe to empty the pipe | |
| 1887 */ | |
| 1888 while ((rv = | |
| 1889 read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) | |
| 1890 == PIPE_BUF){ | |
| 1891 } | |
| 1892 PR_ASSERT((rv > 0) || | |
| 1893 ((rv == -1) && (errno == EAGAIN))); | |
| 1894 } | |
| 1895 if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) | |
| 1896 _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; | |
| 1897 #ifdef IRIX | |
| 1898 if ((me->cpu->id == 0) && | |
| 1899 (FD_ISSET(_pr_irix_primoridal_cp
u_fd[0], rp))) { | |
| 1900 if (_pr_irix_process_exit) { | |
| 1901 /* | |
| 1902 * process exit due to a call to PR_Proc
essExit | |
| 1903 */ | |
| 1904 prctl(PR_SETEXITSIG, SIGKILL); | |
| 1905 _exit(_pr_irix_process_exit_code); | |
| 1906 } else { | |
| 1907 while ((rv = read(_pr_irix_primo
ridal_cpu_fd[0], | |
| 1908 _pr_md_pipebuf, PIPE_BUF
)) == PIPE_BUF) { | |
| 1909 } | |
| 1910 PR_ASSERT(rv > 0); | |
| 1911 } | |
| 1912 } | |
| 1913 if (me->cpu->id == 0) { | |
| 1914 if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_irix_primori
dal_cpu_fd[0]) | |
| 1915 _PR_IOQ_MAX_OSFD(me->cpu) = _pr_irix_pri
moridal_cpu_fd[0]; | |
| 1916 } | |
| 1917 #endif | |
| 1918 } | |
| 1919 } else if (nfd < 0) { | |
| 1920 if (errno == EBADF) { | |
| 1921 FindBadFDs(); | |
| 1922 } else { | |
| 1923 PR_LOG(_pr_io_lm, PR_LOG_MAX, ("select() failed with errno %d", | |
| 1924 errno)); | |
| 1925 } | |
| 1926 } else { | |
| 1927 PR_ASSERT(nfd == 0); | |
| 1928 /* | |
| 1929 * compute the new value of _PR_IOQ_TIMEOUT | |
| 1930 */ | |
| 1931 q = _PR_IOQ(me->cpu).next; | |
| 1932 _PR_IOQ_MAX_OSFD(me->cpu) = -1; | |
| 1933 _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; | |
| 1934 while (q != &_PR_IOQ(me->cpu)) { | |
| 1935 PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); | |
| 1936 _PRUnixPollDesc *pds = pq->pds; | |
| 1937 _PRUnixPollDesc *epds = pds + pq->npds; | |
| 1938 PRInt32 pq_max_osfd = -1; | |
| 1939 | |
| 1940 q = q->next; | |
| 1941 for (; pds < epds; pds++) { | |
| 1942 if (pds->osfd > pq_max_osfd) { | |
| 1943 pq_max_osfd = pds->osfd; | |
| 1944 } | |
| 1945 } | |
| 1946 if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) | |
| 1947 _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; | |
| 1948 if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) | |
| 1949 _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; | |
| 1950 } | |
| 1951 if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { | |
| 1952 if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) | |
| 1953 _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; | |
| 1954 } | |
| 1955 } | |
| 1956 #endif /* _PR_USE_POLL */ | |
| 1957 _PR_MD_IOQ_UNLOCK(); | |
| 1958 } | |
| 1959 | |
| 1960 void _MD_Wakeup_CPUs() | |
| 1961 { | |
| 1962 PRInt32 rv, data; | |
| 1963 | |
| 1964 data = 0; | |
| 1965 rv = write(_pr_md_pipefd[1], &data, 1); | |
| 1966 | |
| 1967 while ((rv < 0) && (errno == EAGAIN)) { | |
| 1968 /* | |
| 1969 * pipe full, read all data in pipe to empty it | |
| 1970 */ | |
| 1971 while ((rv = | |
| 1972 read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) | |
| 1973 == PIPE_BUF) { | |
| 1974 } | |
| 1975 PR_ASSERT((rv > 0) || | |
| 1976 ((rv == -1) && (errno == EAGAIN))); | |
| 1977 rv = write(_pr_md_pipefd[1], &data, 1); | |
| 1978 } | |
| 1979 } | |
| 1980 | |
| 1981 | |
| 1982 void _MD_InitCPUS() | |
| 1983 { | |
| 1984 PRInt32 rv, flags; | |
| 1985 PRThread *me = _MD_CURRENT_THREAD(); | |
| 1986 | |
| 1987 rv = pipe(_pr_md_pipefd); | |
| 1988 PR_ASSERT(rv == 0); | |
| 1989 _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; | |
| 1990 #ifndef _PR_USE_POLL | |
| 1991 FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(me->cpu)); | |
| 1992 #endif | |
| 1993 | |
| 1994 flags = fcntl(_pr_md_pipefd[0], F_GETFL, 0); | |
| 1995 fcntl(_pr_md_pipefd[0], F_SETFL, flags | O_NONBLOCK); | |
| 1996 flags = fcntl(_pr_md_pipefd[1], F_GETFL, 0); | |
| 1997 fcntl(_pr_md_pipefd[1], F_SETFL, flags | O_NONBLOCK); | |
| 1998 } | |
| 1999 | |
| 2000 /* | |
| 2001 ** Unix SIGALRM (clock) signal handler | |
| 2002 */ | |
| 2003 static void ClockInterruptHandler() | |
| 2004 { | |
| 2005 int olderrno; | |
| 2006 PRUintn pri; | |
| 2007 _PRCPU *cpu = _PR_MD_CURRENT_CPU(); | |
| 2008 PRThread *me = _MD_CURRENT_THREAD(); | |
| 2009 | |
| 2010 #ifdef SOLARIS | |
| 2011 if (!me || _PR_IS_NATIVE_THREAD(me)) { | |
| 2012 _pr_primordialCPU->u.missed[_pr_primordialCPU->where] |= _PR_MISSED_CLOC
K; | |
| 2013 return; | |
| 2014 } | |
| 2015 #endif | |
| 2016 | |
| 2017 if (_PR_MD_GET_INTSOFF() != 0) { | |
| 2018 cpu->u.missed[cpu->where] |= _PR_MISSED_CLOCK; | |
| 2019 return; | |
| 2020 } | |
| 2021 _PR_MD_SET_INTSOFF(1); | |
| 2022 | |
| 2023 olderrno = errno; | |
| 2024 _PR_ClockInterrupt(); | |
| 2025 errno = olderrno; | |
| 2026 | |
| 2027 /* | |
| 2028 ** If the interrupt wants a resched or if some other thread at | |
| 2029 ** the same priority needs the cpu, reschedule. | |
| 2030 */ | |
| 2031 pri = me->priority; | |
| 2032 if ((cpu->u.missed[3] || (_PR_RUNQREADYMASK(me->cpu) >> pri))) { | |
| 2033 #ifdef _PR_NO_PREEMPT | |
| 2034 cpu->resched = PR_TRUE; | |
| 2035 if (pr_interruptSwitchHook) { | |
| 2036 (*pr_interruptSwitchHook)(pr_interruptSwitchHookArg); | |
| 2037 } | |
| 2038 #else /* _PR_NO_PREEMPT */ | |
| 2039 /* | |
| 2040 ** Re-enable unix interrupts (so that we can use | |
| 2041 ** setjmp/longjmp for context switching without having to | |
| 2042 ** worry about the signal state) | |
| 2043 */ | |
| 2044 sigprocmask(SIG_SETMASK, &empty_set, 0); | |
| 2045 PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock caused context switch")); | |
| 2046 | |
| 2047 if(!(me->flags & _PR_IDLE_THREAD)) { | |
| 2048 _PR_THREAD_LOCK(me); | |
| 2049 me->state = _PR_RUNNABLE; | |
| 2050 me->cpu = cpu; | |
| 2051 _PR_RUNQ_LOCK(cpu); | |
| 2052 _PR_ADD_RUNQ(me, cpu, pri); | |
| 2053 _PR_RUNQ_UNLOCK(cpu); | |
| 2054 _PR_THREAD_UNLOCK(me); | |
| 2055 } else | |
| 2056 me->state = _PR_RUNNABLE; | |
| 2057 _MD_SWITCH_CONTEXT(me); | |
| 2058 PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock back from context switch")); | |
| 2059 #endif /* _PR_NO_PREEMPT */ | |
| 2060 } | |
| 2061 /* | |
| 2062 * Because this thread could be running on a different cpu after | |
| 2063 * a context switch the current cpu should be accessed and the | |
| 2064 * value of the 'cpu' variable should not be used. | |
| 2065 */ | |
| 2066 _PR_MD_SET_INTSOFF(0); | |
| 2067 } | |
| 2068 | |
| 2069 /* | |
| 2070 * On HP-UX 9, we have to use the sigvector() interface to restart | |
| 2071 * interrupted system calls, because sigaction() does not have the | |
| 2072 * SA_RESTART flag. | |
| 2073 */ | |
| 2074 | |
| 2075 #ifdef HPUX9 | |
| 2076 static void HPUX9_ClockInterruptHandler( | |
| 2077 int sig, | |
| 2078 int code, | |
| 2079 struct sigcontext *scp) | |
| 2080 { | |
| 2081 ClockInterruptHandler(); | |
| 2082 scp->sc_syscall_action = SIG_RESTART; | |
| 2083 } | |
| 2084 #endif /* HPUX9 */ | |
| 2085 | |
| 2086 /* # of milliseconds per clock tick that we will use */ | |
| 2087 #define MSEC_PER_TICK 50 | |
| 2088 | |
| 2089 | |
| 2090 void _MD_StartInterrupts() | |
| 2091 { | |
| 2092 char *eval; | |
| 2093 | |
| 2094 if ((eval = getenv("NSPR_NOCLOCK")) != NULL) { | |
| 2095 if (atoi(eval) == 0) | |
| 2096 _nspr_noclock = 0; | |
| 2097 else | |
| 2098 _nspr_noclock = 1; | |
| 2099 } | |
| 2100 | |
| 2101 #ifndef _PR_NO_CLOCK_TIMER | |
| 2102 if (!_nspr_noclock) { | |
| 2103 _MD_EnableClockInterrupts(); | |
| 2104 } | |
| 2105 #endif | |
| 2106 } | |
| 2107 | |
| 2108 void _MD_StopInterrupts() | |
| 2109 { | |
| 2110 sigprocmask(SIG_BLOCK, &timer_set, 0); | |
| 2111 } | |
| 2112 | |
| 2113 void _MD_EnableClockInterrupts() | |
| 2114 { | |
| 2115 struct itimerval itval; | |
| 2116 extern PRUintn _pr_numCPU; | |
| 2117 #ifdef HPUX9 | |
| 2118 struct sigvec vec; | |
| 2119 | |
| 2120 vec.sv_handler = (void (*)()) HPUX9_ClockInterruptHandler; | |
| 2121 vec.sv_mask = 0; | |
| 2122 vec.sv_flags = 0; | |
| 2123 sigvector(SIGALRM, &vec, 0); | |
| 2124 #else | |
| 2125 struct sigaction vtact; | |
| 2126 | |
| 2127 vtact.sa_handler = (void (*)()) ClockInterruptHandler; | |
| 2128 sigemptyset(&vtact.sa_mask); | |
| 2129 vtact.sa_flags = SA_RESTART; | |
| 2130 sigaction(SIGALRM, &vtact, 0); | |
| 2131 #endif /* HPUX9 */ | |
| 2132 | |
| 2133 PR_ASSERT(_pr_numCPU == 1); | |
| 2134 itval.it_interval.tv_sec = 0; | |
| 2135 itval.it_interval.tv_usec = MSEC_PER_TICK * PR_USEC_PER_MSEC; | |
| 2136 itval.it_value = itval.it_interval; | |
| 2137 setitimer(ITIMER_REAL, &itval, 0); | |
| 2138 } | |
| 2139 | |
| 2140 void _MD_DisableClockInterrupts() | |
| 2141 { | |
| 2142 struct itimerval itval; | |
| 2143 extern PRUintn _pr_numCPU; | |
| 2144 | |
| 2145 PR_ASSERT(_pr_numCPU == 1); | |
| 2146 itval.it_interval.tv_sec = 0; | |
| 2147 itval.it_interval.tv_usec = 0; | |
| 2148 itval.it_value = itval.it_interval; | |
| 2149 setitimer(ITIMER_REAL, &itval, 0); | |
| 2150 } | |
| 2151 | |
| 2152 void _MD_BlockClockInterrupts() | |
| 2153 { | |
| 2154 sigprocmask(SIG_BLOCK, &timer_set, 0); | |
| 2155 } | |
| 2156 | |
| 2157 void _MD_UnblockClockInterrupts() | |
| 2158 { | |
| 2159 sigprocmask(SIG_UNBLOCK, &timer_set, 0); | |
| 2160 } | |
| 2161 | |
| 2162 void _MD_MakeNonblock(PRFileDesc *fd) | |
| 2163 { | |
| 2164 PRInt32 osfd = fd->secret->md.osfd; | |
| 2165 int flags; | |
| 2166 | |
| 2167 if (osfd <= 2) { | |
| 2168 /* Don't mess around with stdin, stdout or stderr */ | |
| 2169 return; | |
| 2170 } | |
| 2171 flags = fcntl(osfd, F_GETFL, 0); | |
| 2172 | |
| 2173 /* | |
| 2174 * Use O_NONBLOCK (POSIX-style non-blocking I/O) whenever possible. | |
| 2175 * On SunOS 4, we must use FNDELAY (BSD-style non-blocking I/O), | |
| 2176 * otherwise connect() still blocks and can be interrupted by SIGALRM. | |
| 2177 */ | |
| 2178 | |
| 2179 fcntl(osfd, F_SETFL, flags | O_NONBLOCK); | |
| 2180 } | |
| 2181 | |
| 2182 PRInt32 _MD_open(const char *name, PRIntn flags, PRIntn mode) | |
| 2183 { | |
| 2184 PRInt32 osflags; | |
| 2185 PRInt32 rv, err; | |
| 2186 | |
| 2187 if (flags & PR_RDWR) { | |
| 2188 osflags = O_RDWR; | |
| 2189 } else if (flags & PR_WRONLY) { | |
| 2190 osflags = O_WRONLY; | |
| 2191 } else { | |
| 2192 osflags = O_RDONLY; | |
| 2193 } | |
| 2194 | |
| 2195 if (flags & PR_EXCL) | |
| 2196 osflags |= O_EXCL; | |
| 2197 if (flags & PR_APPEND) | |
| 2198 osflags |= O_APPEND; | |
| 2199 if (flags & PR_TRUNCATE) | |
| 2200 osflags |= O_TRUNC; | |
| 2201 if (flags & PR_SYNC) { | |
| 2202 #if defined(O_SYNC) | |
| 2203 osflags |= O_SYNC; | |
| 2204 #elif defined(O_FSYNC) | |
| 2205 osflags |= O_FSYNC; | |
| 2206 #else | |
| 2207 #error "Neither O_SYNC nor O_FSYNC is defined on this platform" | |
| 2208 #endif | |
| 2209 } | |
| 2210 | |
| 2211 /* | |
| 2212 ** On creations we hold the 'create' lock in order to enforce | |
| 2213 ** the semantics of PR_Rename. (see the latter for more details) | |
| 2214 */ | |
| 2215 if (flags & PR_CREATE_FILE) | |
| 2216 { | |
| 2217 osflags |= O_CREAT; | |
| 2218 if (NULL !=_pr_rename_lock) | |
| 2219 PR_Lock(_pr_rename_lock); | |
| 2220 } | |
| 2221 | |
| 2222 #if defined(ANDROID) | |
| 2223 osflags |= O_LARGEFILE; | |
| 2224 #endif | |
| 2225 | |
| 2226 rv = _md_iovector._open64(name, osflags, mode); | |
| 2227 | |
| 2228 if (rv < 0) { | |
| 2229 err = _MD_ERRNO(); | |
| 2230 _PR_MD_MAP_OPEN_ERROR(err); | |
| 2231 } | |
| 2232 | |
| 2233 if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock)) | |
| 2234 PR_Unlock(_pr_rename_lock); | |
| 2235 return rv; | |
| 2236 } | |
| 2237 | |
| 2238 PRIntervalTime intr_timeout_ticks; | |
| 2239 | |
| 2240 #if defined(SOLARIS) || defined(IRIX) | |
| 2241 static void sigsegvhandler() { | |
| 2242 fprintf(stderr,"Received SIGSEGV\n"); | |
| 2243 fflush(stderr); | |
| 2244 pause(); | |
| 2245 } | |
| 2246 | |
| 2247 static void sigaborthandler() { | |
| 2248 fprintf(stderr,"Received SIGABRT\n"); | |
| 2249 fflush(stderr); | |
| 2250 pause(); | |
| 2251 } | |
| 2252 | |
| 2253 static void sigbushandler() { | |
| 2254 fprintf(stderr,"Received SIGBUS\n"); | |
| 2255 fflush(stderr); | |
| 2256 pause(); | |
| 2257 } | |
| 2258 #endif /* SOLARIS, IRIX */ | |
| 2259 | |
| 2260 #endif /* !defined(_PR_PTHREADS) */ | |
| 2261 | |
| 2262 void _MD_query_fd_inheritable(PRFileDesc *fd) | |
| 2263 { | |
| 2264 int flags; | |
| 2265 | |
| 2266 PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); | |
| 2267 flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); | |
| 2268 PR_ASSERT(-1 != flags); | |
| 2269 fd->secret->inheritable = (flags & FD_CLOEXEC) ? | |
| 2270 _PR_TRI_FALSE : _PR_TRI_TRUE; | |
| 2271 } | |
| 2272 | |
| 2273 PROffset32 _MD_lseek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) | |
| 2274 { | |
| 2275 PROffset32 rv, where; | |
| 2276 | |
| 2277 switch (whence) { | |
| 2278 case PR_SEEK_SET: | |
| 2279 where = SEEK_SET; | |
| 2280 break; | |
| 2281 case PR_SEEK_CUR: | |
| 2282 where = SEEK_CUR; | |
| 2283 break; | |
| 2284 case PR_SEEK_END: | |
| 2285 where = SEEK_END; | |
| 2286 break; | |
| 2287 default: | |
| 2288 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 2289 rv = -1; | |
| 2290 goto done; | |
| 2291 } | |
| 2292 rv = lseek(fd->secret->md.osfd,offset,where); | |
| 2293 if (rv == -1) | |
| 2294 { | |
| 2295 PRInt32 syserr = _MD_ERRNO(); | |
| 2296 _PR_MD_MAP_LSEEK_ERROR(syserr); | |
| 2297 } | |
| 2298 done: | |
| 2299 return(rv); | |
| 2300 } | |
| 2301 | |
| 2302 PROffset64 _MD_lseek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence) | |
| 2303 { | |
| 2304 PRInt32 where; | |
| 2305 PROffset64 rv; | |
| 2306 | |
| 2307 switch (whence) | |
| 2308 { | |
| 2309 case PR_SEEK_SET: | |
| 2310 where = SEEK_SET; | |
| 2311 break; | |
| 2312 case PR_SEEK_CUR: | |
| 2313 where = SEEK_CUR; | |
| 2314 break; | |
| 2315 case PR_SEEK_END: | |
| 2316 where = SEEK_END; | |
| 2317 break; | |
| 2318 default: | |
| 2319 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 2320 rv = minus_one; | |
| 2321 goto done; | |
| 2322 } | |
| 2323 rv = _md_iovector._lseek64(fd->secret->md.osfd, offset, where); | |
| 2324 if (LL_EQ(rv, minus_one)) | |
| 2325 { | |
| 2326 PRInt32 syserr = _MD_ERRNO(); | |
| 2327 _PR_MD_MAP_LSEEK_ERROR(syserr); | |
| 2328 } | |
| 2329 done: | |
| 2330 return rv; | |
| 2331 } /* _MD_lseek64 */ | |
| 2332 | |
| 2333 /* | |
| 2334 ** _MD_set_fileinfo_times -- | |
| 2335 ** Set the modifyTime and creationTime of the PRFileInfo | |
| 2336 ** structure using the values in struct stat. | |
| 2337 ** | |
| 2338 ** _MD_set_fileinfo64_times -- | |
| 2339 ** Set the modifyTime and creationTime of the PRFileInfo64 | |
| 2340 ** structure using the values in _MDStat64. | |
| 2341 */ | |
| 2342 | |
| 2343 #if defined(_PR_STAT_HAS_ST_ATIM) | |
| 2344 /* | |
| 2345 ** struct stat has st_atim, st_mtim, and st_ctim fields of | |
| 2346 ** type timestruc_t. | |
| 2347 */ | |
| 2348 static void _MD_set_fileinfo_times( | |
| 2349 const struct stat *sb, | |
| 2350 PRFileInfo *info) | |
| 2351 { | |
| 2352 PRInt64 us, s2us; | |
| 2353 | |
| 2354 LL_I2L(s2us, PR_USEC_PER_SEC); | |
| 2355 LL_I2L(info->modifyTime, sb->st_mtim.tv_sec); | |
| 2356 LL_MUL(info->modifyTime, info->modifyTime, s2us); | |
| 2357 LL_I2L(us, sb->st_mtim.tv_nsec / 1000); | |
| 2358 LL_ADD(info->modifyTime, info->modifyTime, us); | |
| 2359 LL_I2L(info->creationTime, sb->st_ctim.tv_sec); | |
| 2360 LL_MUL(info->creationTime, info->creationTime, s2us); | |
| 2361 LL_I2L(us, sb->st_ctim.tv_nsec / 1000); | |
| 2362 LL_ADD(info->creationTime, info->creationTime, us); | |
| 2363 } | |
| 2364 | |
| 2365 static void _MD_set_fileinfo64_times( | |
| 2366 const _MDStat64 *sb, | |
| 2367 PRFileInfo64 *info) | |
| 2368 { | |
| 2369 PRInt64 us, s2us; | |
| 2370 | |
| 2371 LL_I2L(s2us, PR_USEC_PER_SEC); | |
| 2372 LL_I2L(info->modifyTime, sb->st_mtim.tv_sec); | |
| 2373 LL_MUL(info->modifyTime, info->modifyTime, s2us); | |
| 2374 LL_I2L(us, sb->st_mtim.tv_nsec / 1000); | |
| 2375 LL_ADD(info->modifyTime, info->modifyTime, us); | |
| 2376 LL_I2L(info->creationTime, sb->st_ctim.tv_sec); | |
| 2377 LL_MUL(info->creationTime, info->creationTime, s2us); | |
| 2378 LL_I2L(us, sb->st_ctim.tv_nsec / 1000); | |
| 2379 LL_ADD(info->creationTime, info->creationTime, us); | |
| 2380 } | |
| 2381 #elif defined(_PR_STAT_HAS_ST_ATIM_UNION) | |
| 2382 /* | |
| 2383 ** The st_atim, st_mtim, and st_ctim fields in struct stat are | |
| 2384 ** unions with a st__tim union member of type timestruc_t. | |
| 2385 */ | |
| 2386 static void _MD_set_fileinfo_times( | |
| 2387 const struct stat *sb, | |
| 2388 PRFileInfo *info) | |
| 2389 { | |
| 2390 PRInt64 us, s2us; | |
| 2391 | |
| 2392 LL_I2L(s2us, PR_USEC_PER_SEC); | |
| 2393 LL_I2L(info->modifyTime, sb->st_mtim.st__tim.tv_sec); | |
| 2394 LL_MUL(info->modifyTime, info->modifyTime, s2us); | |
| 2395 LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000); | |
| 2396 LL_ADD(info->modifyTime, info->modifyTime, us); | |
| 2397 LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec); | |
| 2398 LL_MUL(info->creationTime, info->creationTime, s2us); | |
| 2399 LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000); | |
| 2400 LL_ADD(info->creationTime, info->creationTime, us); | |
| 2401 } | |
| 2402 | |
| 2403 static void _MD_set_fileinfo64_times( | |
| 2404 const _MDStat64 *sb, | |
| 2405 PRFileInfo64 *info) | |
| 2406 { | |
| 2407 PRInt64 us, s2us; | |
| 2408 | |
| 2409 LL_I2L(s2us, PR_USEC_PER_SEC); | |
| 2410 LL_I2L(info->modifyTime, sb->st_mtim.st__tim.tv_sec); | |
| 2411 LL_MUL(info->modifyTime, info->modifyTime, s2us); | |
| 2412 LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000); | |
| 2413 LL_ADD(info->modifyTime, info->modifyTime, us); | |
| 2414 LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec); | |
| 2415 LL_MUL(info->creationTime, info->creationTime, s2us); | |
| 2416 LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000); | |
| 2417 LL_ADD(info->creationTime, info->creationTime, us); | |
| 2418 } | |
| 2419 #elif defined(_PR_STAT_HAS_ST_ATIMESPEC) | |
| 2420 /* | |
| 2421 ** struct stat has st_atimespec, st_mtimespec, and st_ctimespec | |
| 2422 ** fields of type struct timespec. | |
| 2423 */ | |
| 2424 #if defined(_PR_TIMESPEC_HAS_TS_SEC) | |
| 2425 static void _MD_set_fileinfo_times( | |
| 2426 const struct stat *sb, | |
| 2427 PRFileInfo *info) | |
| 2428 { | |
| 2429 PRInt64 us, s2us; | |
| 2430 | |
| 2431 LL_I2L(s2us, PR_USEC_PER_SEC); | |
| 2432 LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec); | |
| 2433 LL_MUL(info->modifyTime, info->modifyTime, s2us); | |
| 2434 LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000); | |
| 2435 LL_ADD(info->modifyTime, info->modifyTime, us); | |
| 2436 LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec); | |
| 2437 LL_MUL(info->creationTime, info->creationTime, s2us); | |
| 2438 LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000); | |
| 2439 LL_ADD(info->creationTime, info->creationTime, us); | |
| 2440 } | |
| 2441 | |
| 2442 static void _MD_set_fileinfo64_times( | |
| 2443 const _MDStat64 *sb, | |
| 2444 PRFileInfo64 *info) | |
| 2445 { | |
| 2446 PRInt64 us, s2us; | |
| 2447 | |
| 2448 LL_I2L(s2us, PR_USEC_PER_SEC); | |
| 2449 LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec); | |
| 2450 LL_MUL(info->modifyTime, info->modifyTime, s2us); | |
| 2451 LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000); | |
| 2452 LL_ADD(info->modifyTime, info->modifyTime, us); | |
| 2453 LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec); | |
| 2454 LL_MUL(info->creationTime, info->creationTime, s2us); | |
| 2455 LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000); | |
| 2456 LL_ADD(info->creationTime, info->creationTime, us); | |
| 2457 } | |
| 2458 #else /* _PR_TIMESPEC_HAS_TS_SEC */ | |
| 2459 /* | |
| 2460 ** The POSIX timespec structure has tv_sec and tv_nsec. | |
| 2461 */ | |
| 2462 static void _MD_set_fileinfo_times( | |
| 2463 const struct stat *sb, | |
| 2464 PRFileInfo *info) | |
| 2465 { | |
| 2466 PRInt64 us, s2us; | |
| 2467 | |
| 2468 LL_I2L(s2us, PR_USEC_PER_SEC); | |
| 2469 LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec); | |
| 2470 LL_MUL(info->modifyTime, info->modifyTime, s2us); | |
| 2471 LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000); | |
| 2472 LL_ADD(info->modifyTime, info->modifyTime, us); | |
| 2473 LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec); | |
| 2474 LL_MUL(info->creationTime, info->creationTime, s2us); | |
| 2475 LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000); | |
| 2476 LL_ADD(info->creationTime, info->creationTime, us); | |
| 2477 } | |
| 2478 | |
| 2479 static void _MD_set_fileinfo64_times( | |
| 2480 const _MDStat64 *sb, | |
| 2481 PRFileInfo64 *info) | |
| 2482 { | |
| 2483 PRInt64 us, s2us; | |
| 2484 | |
| 2485 LL_I2L(s2us, PR_USEC_PER_SEC); | |
| 2486 LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec); | |
| 2487 LL_MUL(info->modifyTime, info->modifyTime, s2us); | |
| 2488 LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000); | |
| 2489 LL_ADD(info->modifyTime, info->modifyTime, us); | |
| 2490 LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec); | |
| 2491 LL_MUL(info->creationTime, info->creationTime, s2us); | |
| 2492 LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000); | |
| 2493 LL_ADD(info->creationTime, info->creationTime, us); | |
| 2494 } | |
| 2495 #endif /* _PR_TIMESPEC_HAS_TS_SEC */ | |
| 2496 #elif defined(_PR_STAT_HAS_ONLY_ST_ATIME) | |
| 2497 /* | |
| 2498 ** struct stat only has st_atime, st_mtime, and st_ctime fields | |
| 2499 ** of type time_t. | |
| 2500 */ | |
| 2501 static void _MD_set_fileinfo_times( | |
| 2502 const struct stat *sb, | |
| 2503 PRFileInfo *info) | |
| 2504 { | |
| 2505 PRInt64 s, s2us; | |
| 2506 LL_I2L(s2us, PR_USEC_PER_SEC); | |
| 2507 LL_I2L(s, sb->st_mtime); | |
| 2508 LL_MUL(s, s, s2us); | |
| 2509 info->modifyTime = s; | |
| 2510 LL_I2L(s, sb->st_ctime); | |
| 2511 LL_MUL(s, s, s2us); | |
| 2512 info->creationTime = s; | |
| 2513 } | |
| 2514 | |
| 2515 static void _MD_set_fileinfo64_times( | |
| 2516 const _MDStat64 *sb, | |
| 2517 PRFileInfo64 *info) | |
| 2518 { | |
| 2519 PRInt64 s, s2us; | |
| 2520 LL_I2L(s2us, PR_USEC_PER_SEC); | |
| 2521 LL_I2L(s, sb->st_mtime); | |
| 2522 LL_MUL(s, s, s2us); | |
| 2523 info->modifyTime = s; | |
| 2524 LL_I2L(s, sb->st_ctime); | |
| 2525 LL_MUL(s, s, s2us); | |
| 2526 info->creationTime = s; | |
| 2527 } | |
| 2528 #else | |
| 2529 #error "I don't know yet" | |
| 2530 #endif | |
| 2531 | |
| 2532 static int _MD_convert_stat_to_fileinfo( | |
| 2533 const struct stat *sb, | |
| 2534 PRFileInfo *info) | |
| 2535 { | |
| 2536 if (S_IFREG & sb->st_mode) | |
| 2537 info->type = PR_FILE_FILE; | |
| 2538 else if (S_IFDIR & sb->st_mode) | |
| 2539 info->type = PR_FILE_DIRECTORY; | |
| 2540 else | |
| 2541 info->type = PR_FILE_OTHER; | |
| 2542 | |
| 2543 #if defined(_PR_HAVE_LARGE_OFF_T) | |
| 2544 if (0x7fffffffL < sb->st_size) | |
| 2545 { | |
| 2546 PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); | |
| 2547 return -1; | |
| 2548 } | |
| 2549 #endif /* defined(_PR_HAVE_LARGE_OFF_T) */ | |
| 2550 info->size = sb->st_size; | |
| 2551 | |
| 2552 _MD_set_fileinfo_times(sb, info); | |
| 2553 return 0; | |
| 2554 } /* _MD_convert_stat_to_fileinfo */ | |
| 2555 | |
| 2556 static int _MD_convert_stat64_to_fileinfo64( | |
| 2557 const _MDStat64 *sb, | |
| 2558 PRFileInfo64 *info) | |
| 2559 { | |
| 2560 if (S_IFREG & sb->st_mode) | |
| 2561 info->type = PR_FILE_FILE; | |
| 2562 else if (S_IFDIR & sb->st_mode) | |
| 2563 info->type = PR_FILE_DIRECTORY; | |
| 2564 else | |
| 2565 info->type = PR_FILE_OTHER; | |
| 2566 | |
| 2567 LL_I2L(info->size, sb->st_size); | |
| 2568 | |
| 2569 _MD_set_fileinfo64_times(sb, info); | |
| 2570 return 0; | |
| 2571 } /* _MD_convert_stat64_to_fileinfo64 */ | |
| 2572 | |
| 2573 PRInt32 _MD_getfileinfo(const char *fn, PRFileInfo *info) | |
| 2574 { | |
| 2575 PRInt32 rv; | |
| 2576 struct stat sb; | |
| 2577 | |
| 2578 rv = stat(fn, &sb); | |
| 2579 if (rv < 0) | |
| 2580 _PR_MD_MAP_STAT_ERROR(_MD_ERRNO()); | |
| 2581 else if (NULL != info) | |
| 2582 rv = _MD_convert_stat_to_fileinfo(&sb, info); | |
| 2583 return rv; | |
| 2584 } | |
| 2585 | |
| 2586 PRInt32 _MD_getfileinfo64(const char *fn, PRFileInfo64 *info) | |
| 2587 { | |
| 2588 _MDStat64 sb; | |
| 2589 PRInt32 rv = _md_iovector._stat64(fn, &sb); | |
| 2590 if (rv < 0) | |
| 2591 _PR_MD_MAP_STAT_ERROR(_MD_ERRNO()); | |
| 2592 else if (NULL != info) | |
| 2593 rv = _MD_convert_stat64_to_fileinfo64(&sb, info); | |
| 2594 return rv; | |
| 2595 } | |
| 2596 | |
| 2597 PRInt32 _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info) | |
| 2598 { | |
| 2599 struct stat sb; | |
| 2600 PRInt32 rv = fstat(fd->secret->md.osfd, &sb); | |
| 2601 if (rv < 0) | |
| 2602 _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO()); | |
| 2603 else if (NULL != info) | |
| 2604 rv = _MD_convert_stat_to_fileinfo(&sb, info); | |
| 2605 return rv; | |
| 2606 } | |
| 2607 | |
| 2608 PRInt32 _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info) | |
| 2609 { | |
| 2610 _MDStat64 sb; | |
| 2611 PRInt32 rv = _md_iovector._fstat64(fd->secret->md.osfd, &sb); | |
| 2612 if (rv < 0) | |
| 2613 _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO()); | |
| 2614 else if (NULL != info) | |
| 2615 rv = _MD_convert_stat64_to_fileinfo64(&sb, info); | |
| 2616 return rv; | |
| 2617 } | |
| 2618 | |
| 2619 /* | |
| 2620 * _md_iovector._open64 must be initialized to 'open' so that _PR_InitLog can | |
| 2621 * open the log file during NSPR initialization, before _md_iovector is | |
| 2622 * initialized by _PR_MD_FINAL_INIT. This means the log file cannot be a | |
| 2623 * large file on some platforms. | |
| 2624 */ | |
| 2625 #ifdef SYMBIAN | |
| 2626 struct _MD_IOVector _md_iovector; /* Will crash if NSPR_LOG_FILE is set. */ | |
| 2627 #else | |
| 2628 struct _MD_IOVector _md_iovector = { open }; | |
| 2629 #endif | |
| 2630 | |
| 2631 /* | |
| 2632 ** These implementations are to emulate large file routines on systems that | |
| 2633 ** don't have them. Their goal is to check in case overflow occurs. Otherwise | |
| 2634 ** they will just operate as normal using 32-bit file routines. | |
| 2635 ** | |
| 2636 ** The checking might be pre- or post-op, depending on the semantics. | |
| 2637 */ | |
| 2638 | |
| 2639 #if defined(SOLARIS2_5) | |
| 2640 | |
| 2641 static PRIntn _MD_solaris25_fstat64(PRIntn osfd, _MDStat64 *buf) | |
| 2642 { | |
| 2643 PRInt32 rv; | |
| 2644 struct stat sb; | |
| 2645 | |
| 2646 rv = fstat(osfd, &sb); | |
| 2647 if (rv >= 0) | |
| 2648 { | |
| 2649 /* | |
| 2650 ** I'm only copying the fields that are immediately needed. | |
| 2651 ** If somebody else calls this function, some of the fields | |
| 2652 ** may not be defined. | |
| 2653 */ | |
| 2654 (void)memset(buf, 0, sizeof(_MDStat64)); | |
| 2655 buf->st_mode = sb.st_mode; | |
| 2656 buf->st_ctim = sb.st_ctim; | |
| 2657 buf->st_mtim = sb.st_mtim; | |
| 2658 buf->st_size = sb.st_size; | |
| 2659 } | |
| 2660 return rv; | |
| 2661 } /* _MD_solaris25_fstat64 */ | |
| 2662 | |
| 2663 static PRIntn _MD_solaris25_stat64(const char *fn, _MDStat64 *buf) | |
| 2664 { | |
| 2665 PRInt32 rv; | |
| 2666 struct stat sb; | |
| 2667 | |
| 2668 rv = stat(fn, &sb); | |
| 2669 if (rv >= 0) | |
| 2670 { | |
| 2671 /* | |
| 2672 ** I'm only copying the fields that are immediately needed. | |
| 2673 ** If somebody else calls this function, some of the fields | |
| 2674 ** may not be defined. | |
| 2675 */ | |
| 2676 (void)memset(buf, 0, sizeof(_MDStat64)); | |
| 2677 buf->st_mode = sb.st_mode; | |
| 2678 buf->st_ctim = sb.st_ctim; | |
| 2679 buf->st_mtim = sb.st_mtim; | |
| 2680 buf->st_size = sb.st_size; | |
| 2681 } | |
| 2682 return rv; | |
| 2683 } /* _MD_solaris25_stat64 */ | |
| 2684 #endif /* defined(SOLARIS2_5) */ | |
| 2685 | |
| 2686 #if defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5) | |
| 2687 | |
| 2688 static PROffset64 _MD_Unix_lseek64(PRIntn osfd, PROffset64 offset, PRIntn whence
) | |
| 2689 { | |
| 2690 PRUint64 maxoff; | |
| 2691 PROffset64 rv = minus_one; | |
| 2692 LL_I2L(maxoff, 0x7fffffff); | |
| 2693 if (LL_CMP(offset, <=, maxoff)) | |
| 2694 { | |
| 2695 off_t off; | |
| 2696 LL_L2I(off, offset); | |
| 2697 LL_I2L(rv, lseek(osfd, off, whence)); | |
| 2698 } | |
| 2699 else errno = EFBIG; /* we can't go there */ | |
| 2700 return rv; | |
| 2701 } /* _MD_Unix_lseek64 */ | |
| 2702 | |
| 2703 static void* _MD_Unix_mmap64( | |
| 2704 void *addr, PRSize len, PRIntn prot, PRIntn flags, | |
| 2705 PRIntn fildes, PRInt64 offset) | |
| 2706 { | |
| 2707 PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); | |
| 2708 return NULL; | |
| 2709 } /* _MD_Unix_mmap64 */ | |
| 2710 #endif /* defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5) */ | |
| 2711 | |
| 2712 /* Android doesn't have mmap64. */ | |
| 2713 #if defined(ANDROID) | |
| 2714 extern void *__mmap2(void *, size_t, int, int, int, size_t); | |
| 2715 | |
| 2716 #define ANDROID_PAGE_SIZE 4096 | |
| 2717 | |
| 2718 static void * | |
| 2719 mmap64(void *addr, size_t len, int prot, int flags, int fd, loff_t offset) | |
| 2720 { | |
| 2721 if (offset & (ANDROID_PAGE_SIZE - 1)) { | |
| 2722 errno = EINVAL; | |
| 2723 return MAP_FAILED; | |
| 2724 } | |
| 2725 return __mmap2(addr, len, prot, flags, fd, offset / ANDROID_PAGE_SIZE); | |
| 2726 } | |
| 2727 #endif | |
| 2728 | |
| 2729 #if defined(OSF1) && defined(__GNUC__) | |
| 2730 | |
| 2731 /* | |
| 2732 * On OSF1 V5.0A, <sys/stat.h> defines stat and fstat as | |
| 2733 * macros when compiled under gcc, so it is rather tricky to | |
| 2734 * take the addresses of the real functions the macros expend | |
| 2735 * to. A simple solution is to define forwarder functions | |
| 2736 * and take the addresses of the forwarder functions instead. | |
| 2737 */ | |
| 2738 | |
| 2739 static int stat_forwarder(const char *path, struct stat *buffer) | |
| 2740 { | |
| 2741 return stat(path, buffer); | |
| 2742 } | |
| 2743 | |
| 2744 static int fstat_forwarder(int filedes, struct stat *buffer) | |
| 2745 { | |
| 2746 return fstat(filedes, buffer); | |
| 2747 } | |
| 2748 | |
| 2749 #endif | |
| 2750 | |
| 2751 static void _PR_InitIOV(void) | |
| 2752 { | |
| 2753 #if defined(SOLARIS2_5) | |
| 2754 PRLibrary *lib; | |
| 2755 void *open64_func; | |
| 2756 | |
| 2757 open64_func = PR_FindSymbolAndLibrary("open64", &lib); | |
| 2758 if (NULL != open64_func) | |
| 2759 { | |
| 2760 PR_ASSERT(NULL != lib); | |
| 2761 _md_iovector._open64 = (_MD_Open64)open64_func; | |
| 2762 _md_iovector._mmap64 = (_MD_Mmap64)PR_FindSymbol(lib, "mmap64"); | |
| 2763 _md_iovector._fstat64 = (_MD_Fstat64)PR_FindSymbol(lib, "fstat64"); | |
| 2764 _md_iovector._stat64 = (_MD_Stat64)PR_FindSymbol(lib, "stat64"); | |
| 2765 _md_iovector._lseek64 = (_MD_Lseek64)PR_FindSymbol(lib, "lseek64"); | |
| 2766 (void)PR_UnloadLibrary(lib); | |
| 2767 } | |
| 2768 else | |
| 2769 { | |
| 2770 _md_iovector._open64 = open; | |
| 2771 _md_iovector._mmap64 = _MD_Unix_mmap64; | |
| 2772 _md_iovector._fstat64 = _MD_solaris25_fstat64; | |
| 2773 _md_iovector._stat64 = _MD_solaris25_stat64; | |
| 2774 _md_iovector._lseek64 = _MD_Unix_lseek64; | |
| 2775 } | |
| 2776 #elif defined(_PR_NO_LARGE_FILES) | |
| 2777 _md_iovector._open64 = open; | |
| 2778 _md_iovector._mmap64 = _MD_Unix_mmap64; | |
| 2779 _md_iovector._fstat64 = fstat; | |
| 2780 _md_iovector._stat64 = stat; | |
| 2781 _md_iovector._lseek64 = _MD_Unix_lseek64; | |
| 2782 #elif defined(_PR_HAVE_OFF64_T) | |
| 2783 #if defined(IRIX5_3) || defined(ANDROID) | |
| 2784 /* | |
| 2785 * Android doesn't have open64. We pass the O_LARGEFILE flag to open | |
| 2786 * in _MD_open. | |
| 2787 */ | |
| 2788 _md_iovector._open64 = open; | |
| 2789 #else | |
| 2790 _md_iovector._open64 = open64; | |
| 2791 #endif | |
| 2792 _md_iovector._mmap64 = mmap64; | |
| 2793 _md_iovector._fstat64 = fstat64; | |
| 2794 _md_iovector._stat64 = stat64; | |
| 2795 _md_iovector._lseek64 = lseek64; | |
| 2796 #elif defined(_PR_HAVE_LARGE_OFF_T) | |
| 2797 _md_iovector._open64 = open; | |
| 2798 _md_iovector._mmap64 = mmap; | |
| 2799 #if defined(OSF1) && defined(__GNUC__) | |
| 2800 _md_iovector._fstat64 = fstat_forwarder; | |
| 2801 _md_iovector._stat64 = stat_forwarder; | |
| 2802 #else | |
| 2803 _md_iovector._fstat64 = fstat; | |
| 2804 _md_iovector._stat64 = stat; | |
| 2805 #endif | |
| 2806 _md_iovector._lseek64 = lseek; | |
| 2807 #else | |
| 2808 #error "I don't know yet" | |
| 2809 #endif | |
| 2810 LL_I2L(minus_one, -1); | |
| 2811 } /* _PR_InitIOV */ | |
| 2812 | |
| 2813 void _PR_UnixInit(void) | |
| 2814 { | |
| 2815 struct sigaction sigact; | |
| 2816 int rv; | |
| 2817 | |
| 2818 sigemptyset(&timer_set); | |
| 2819 | |
| 2820 #if !defined(_PR_PTHREADS) | |
| 2821 | |
| 2822 sigaddset(&timer_set, SIGALRM); | |
| 2823 sigemptyset(&empty_set); | |
| 2824 intr_timeout_ticks = | |
| 2825 PR_SecondsToInterval(_PR_INTERRUPT_CHECK_INTERVAL_SECS); | |
| 2826 | |
| 2827 #if defined(SOLARIS) || defined(IRIX) | |
| 2828 | |
| 2829 if (getenv("NSPR_SIGSEGV_HANDLE")) { | |
| 2830 sigact.sa_handler = sigsegvhandler; | |
| 2831 sigact.sa_flags = 0; | |
| 2832 sigact.sa_mask = timer_set; | |
| 2833 sigaction(SIGSEGV, &sigact, 0); | |
| 2834 } | |
| 2835 | |
| 2836 if (getenv("NSPR_SIGABRT_HANDLE")) { | |
| 2837 sigact.sa_handler = sigaborthandler; | |
| 2838 sigact.sa_flags = 0; | |
| 2839 sigact.sa_mask = timer_set; | |
| 2840 sigaction(SIGABRT, &sigact, 0); | |
| 2841 } | |
| 2842 | |
| 2843 if (getenv("NSPR_SIGBUS_HANDLE")) { | |
| 2844 sigact.sa_handler = sigbushandler; | |
| 2845 sigact.sa_flags = 0; | |
| 2846 sigact.sa_mask = timer_set; | |
| 2847 sigaction(SIGBUS, &sigact, 0); | |
| 2848 } | |
| 2849 | |
| 2850 #endif | |
| 2851 #endif /* !defined(_PR_PTHREADS) */ | |
| 2852 | |
| 2853 /* | |
| 2854 * Under HP-UX DCE threads, sigaction() installs a per-thread | |
| 2855 * handler, so we use sigvector() to install a process-wide | |
| 2856 * handler. | |
| 2857 */ | |
| 2858 #if defined(HPUX) && defined(_PR_DCETHREADS) | |
| 2859 { | |
| 2860 struct sigvec vec; | |
| 2861 | |
| 2862 vec.sv_handler = SIG_IGN; | |
| 2863 vec.sv_mask = 0; | |
| 2864 vec.sv_flags = 0; | |
| 2865 rv = sigvector(SIGPIPE, &vec, NULL); | |
| 2866 PR_ASSERT(0 == rv); | |
| 2867 } | |
| 2868 #else | |
| 2869 sigact.sa_handler = SIG_IGN; | |
| 2870 sigemptyset(&sigact.sa_mask); | |
| 2871 sigact.sa_flags = 0; | |
| 2872 rv = sigaction(SIGPIPE, &sigact, 0); | |
| 2873 PR_ASSERT(0 == rv); | |
| 2874 #endif /* HPUX && _PR_DCETHREADS */ | |
| 2875 | |
| 2876 _pr_rename_lock = PR_NewLock(); | |
| 2877 PR_ASSERT(NULL != _pr_rename_lock); | |
| 2878 _pr_Xfe_mon = PR_NewMonitor(); | |
| 2879 PR_ASSERT(NULL != _pr_Xfe_mon); | |
| 2880 | |
| 2881 _PR_InitIOV(); /* one last hack */ | |
| 2882 } | |
| 2883 | |
| 2884 void _PR_UnixCleanup(void) | |
| 2885 { | |
| 2886 if (_pr_rename_lock) { | |
| 2887 PR_DestroyLock(_pr_rename_lock); | |
| 2888 _pr_rename_lock = NULL; | |
| 2889 } | |
| 2890 if (_pr_Xfe_mon) { | |
| 2891 PR_DestroyMonitor(_pr_Xfe_mon); | |
| 2892 _pr_Xfe_mon = NULL; | |
| 2893 } | |
| 2894 } | |
| 2895 | |
| 2896 #if !defined(_PR_PTHREADS) | |
| 2897 | |
| 2898 /* | |
| 2899 * Variables used by the GC code, initialized in _MD_InitSegs(). | |
| 2900 */ | |
| 2901 static PRInt32 _pr_zero_fd = -1; | |
| 2902 static PRLock *_pr_md_lock = NULL; | |
| 2903 | |
| 2904 /* | |
| 2905 * _MD_InitSegs -- | |
| 2906 * | |
| 2907 * This is Unix's version of _PR_MD_INIT_SEGS(), which is | |
| 2908 * called by _PR_InitSegs(), which in turn is called by | |
| 2909 * PR_Init(). | |
| 2910 */ | |
| 2911 void _MD_InitSegs(void) | |
| 2912 { | |
| 2913 #ifdef DEBUG | |
| 2914 /* | |
| 2915 ** Disable using mmap(2) if NSPR_NO_MMAP is set | |
| 2916 */ | |
| 2917 if (getenv("NSPR_NO_MMAP")) { | |
| 2918 _pr_zero_fd = -2; | |
| 2919 return; | |
| 2920 } | |
| 2921 #endif | |
| 2922 _pr_zero_fd = open("/dev/zero",O_RDWR , 0); | |
| 2923 /* Prevent the fd from being inherited by child processes */ | |
| 2924 fcntl(_pr_zero_fd, F_SETFD, FD_CLOEXEC); | |
| 2925 _pr_md_lock = PR_NewLock(); | |
| 2926 } | |
| 2927 | |
| 2928 PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr) | |
| 2929 { | |
| 2930 static char *lastaddr = (char*) _PR_STACK_VMBASE; | |
| 2931 PRStatus retval = PR_SUCCESS; | |
| 2932 int prot; | |
| 2933 void *rv; | |
| 2934 | |
| 2935 PR_ASSERT(seg != 0); | |
| 2936 PR_ASSERT(size != 0); | |
| 2937 | |
| 2938 PR_Lock(_pr_md_lock); | |
| 2939 if (_pr_zero_fd < 0) { | |
| 2940 from_heap: | |
| 2941 seg->vaddr = PR_MALLOC(size); | |
| 2942 if (!seg->vaddr) { | |
| 2943 retval = PR_FAILURE; | |
| 2944 } | |
| 2945 else { | |
| 2946 seg->size = size; | |
| 2947 } | |
| 2948 goto exit; | |
| 2949 } | |
| 2950 | |
| 2951 prot = PROT_READ|PROT_WRITE; | |
| 2952 /* | |
| 2953 * On Alpha Linux, the user-level thread stack needs | |
| 2954 * to be made executable because longjmp/signal seem | |
| 2955 * to put machine instructions on the stack. | |
| 2956 */ | |
| 2957 #if defined(LINUX) && defined(__alpha) | |
| 2958 prot |= PROT_EXEC; | |
| 2959 #endif | |
| 2960 rv = mmap((vaddr != 0) ? vaddr : lastaddr, size, prot, | |
| 2961 _MD_MMAP_FLAGS, | |
| 2962 _pr_zero_fd, 0); | |
| 2963 if (rv == (void*)-1) { | |
| 2964 goto from_heap; | |
| 2965 } | |
| 2966 lastaddr += size; | |
| 2967 seg->vaddr = rv; | |
| 2968 seg->size = size; | |
| 2969 seg->flags = _PR_SEG_VM; | |
| 2970 | |
| 2971 exit: | |
| 2972 PR_Unlock(_pr_md_lock); | |
| 2973 return retval; | |
| 2974 } | |
| 2975 | |
| 2976 void _MD_FreeSegment(PRSegment *seg) | |
| 2977 { | |
| 2978 if (seg->flags & _PR_SEG_VM) | |
| 2979 (void) munmap(seg->vaddr, seg->size); | |
| 2980 else | |
| 2981 PR_DELETE(seg->vaddr); | |
| 2982 } | |
| 2983 | |
| 2984 #endif /* _PR_PTHREADS */ | |
| 2985 | |
| 2986 /* | |
| 2987 *----------------------------------------------------------------------- | |
| 2988 * | |
| 2989 * PR_Now -- | |
| 2990 * | |
| 2991 * Returns the current time in microseconds since the epoch. | |
| 2992 * The epoch is midnight January 1, 1970 GMT. | |
| 2993 * The implementation is machine dependent. This is the Unix | |
| 2994 * implementation. | |
| 2995 * Cf. time_t time(time_t *tp) | |
| 2996 * | |
| 2997 *----------------------------------------------------------------------- | |
| 2998 */ | |
| 2999 | |
| 3000 PR_IMPLEMENT(PRTime) | |
| 3001 PR_Now(void) | |
| 3002 { | |
| 3003 struct timeval tv; | |
| 3004 PRInt64 s, us, s2us; | |
| 3005 | |
| 3006 GETTIMEOFDAY(&tv); | |
| 3007 LL_I2L(s2us, PR_USEC_PER_SEC); | |
| 3008 LL_I2L(s, tv.tv_sec); | |
| 3009 LL_I2L(us, tv.tv_usec); | |
| 3010 LL_MUL(s, s, s2us); | |
| 3011 LL_ADD(s, s, us); | |
| 3012 return s; | |
| 3013 } | |
| 3014 | |
| 3015 #if defined(_MD_INTERVAL_USE_GTOD) | |
| 3016 /* | |
| 3017 * This version of interval times is based on the time of day | |
| 3018 * capability offered by the system. This isn't valid for two reasons: | |
| 3019 * 1) The time of day is neither linear nor montonically increasing | |
| 3020 * 2) The units here are milliseconds. That's not appropriate for our use. | |
| 3021 */ | |
| 3022 PRIntervalTime _PR_UNIX_GetInterval() | |
| 3023 { | |
| 3024 struct timeval time; | |
| 3025 PRIntervalTime ticks; | |
| 3026 | |
| 3027 (void)GETTIMEOFDAY(&time); /* fallicy of course */ | |
| 3028 ticks = (PRUint32)time.tv_sec * PR_MSEC_PER_SEC; /* that's in milliseconds
*/ | |
| 3029 ticks += (PRUint32)time.tv_usec / PR_USEC_PER_MSEC; /* so's that */ | |
| 3030 return ticks; | |
| 3031 } /* _PR_UNIX_GetInterval */ | |
| 3032 | |
| 3033 PRIntervalTime _PR_UNIX_TicksPerSecond() | |
| 3034 { | |
| 3035 return 1000; /* this needs some work :) */ | |
| 3036 } | |
| 3037 #endif | |
| 3038 | |
| 3039 #if defined(HAVE_CLOCK_MONOTONIC) | |
| 3040 PRIntervalTime _PR_UNIX_GetInterval2() | |
| 3041 { | |
| 3042 struct timespec time; | |
| 3043 PRIntervalTime ticks; | |
| 3044 | |
| 3045 if (clock_gettime(CLOCK_MONOTONIC, &time) != 0) { | |
| 3046 fprintf(stderr, "clock_gettime failed: %d\n", errno); | |
| 3047 abort(); | |
| 3048 } | |
| 3049 | |
| 3050 ticks = (PRUint32)time.tv_sec * PR_MSEC_PER_SEC; | |
| 3051 ticks += (PRUint32)time.tv_nsec / PR_NSEC_PER_MSEC; | |
| 3052 return ticks; | |
| 3053 } | |
| 3054 | |
| 3055 PRIntervalTime _PR_UNIX_TicksPerSecond2() | |
| 3056 { | |
| 3057 return 1000; | |
| 3058 } | |
| 3059 #endif | |
| 3060 | |
| 3061 #if !defined(_PR_PTHREADS) | |
| 3062 /* | |
| 3063 * Wait for I/O on multiple descriptors. | |
| 3064 * | |
| 3065 * Return 0 if timed out, return -1 if interrupted, | |
| 3066 * else return the number of ready descriptors. | |
| 3067 */ | |
| 3068 PRInt32 _PR_WaitForMultipleFDs( | |
| 3069 _PRUnixPollDesc *unixpds, | |
| 3070 PRInt32 pdcnt, | |
| 3071 PRIntervalTime timeout) | |
| 3072 { | |
| 3073 PRPollQueue pq; | |
| 3074 PRIntn is; | |
| 3075 PRInt32 rv; | |
| 3076 _PRCPU *io_cpu; | |
| 3077 _PRUnixPollDesc *unixpd, *eunixpd; | |
| 3078 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 3079 | |
| 3080 PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); | |
| 3081 | |
| 3082 if (_PR_PENDING_INTERRUPT(me)) { | |
| 3083 me->flags &= ~_PR_INTERRUPT; | |
| 3084 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
| 3085 return -1; | |
| 3086 } | |
| 3087 | |
| 3088 pq.pds = unixpds; | |
| 3089 pq.npds = pdcnt; | |
| 3090 | |
| 3091 _PR_INTSOFF(is); | |
| 3092 _PR_MD_IOQ_LOCK(); | |
| 3093 _PR_THREAD_LOCK(me); | |
| 3094 | |
| 3095 pq.thr = me; | |
| 3096 io_cpu = me->cpu; | |
| 3097 pq.on_ioq = PR_TRUE; | |
| 3098 pq.timeout = timeout; | |
| 3099 _PR_ADD_TO_IOQ(pq, me->cpu); | |
| 3100 | |
| 3101 #if !defined(_PR_USE_POLL) | |
| 3102 eunixpd = unixpds + pdcnt; | |
| 3103 for (unixpd = unixpds; unixpd < eunixpd; unixpd++) { | |
| 3104 PRInt32 osfd = unixpd->osfd; | |
| 3105 if (unixpd->in_flags & _PR_UNIX_POLL_READ) { | |
| 3106 FD_SET(osfd, &_PR_FD_READ_SET(me->cpu)); | |
| 3107 _PR_FD_READ_CNT(me->cpu)[osfd]++; | |
| 3108 } | |
| 3109 if (unixpd->in_flags & _PR_UNIX_POLL_WRITE) { | |
| 3110 FD_SET(osfd, &_PR_FD_WRITE_SET(me->cpu)); | |
| 3111 (_PR_FD_WRITE_CNT(me->cpu))[osfd]++; | |
| 3112 } | |
| 3113 if (unixpd->in_flags & _PR_UNIX_POLL_EXCEPT) { | |
| 3114 FD_SET(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); | |
| 3115 (_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]++; | |
| 3116 } | |
| 3117 if (osfd > _PR_IOQ_MAX_OSFD(me->cpu)) { | |
| 3118 _PR_IOQ_MAX_OSFD(me->cpu) = osfd; | |
| 3119 } | |
| 3120 } | |
| 3121 #endif /* !defined(_PR_USE_POLL) */ | |
| 3122 | |
| 3123 if (_PR_IOQ_TIMEOUT(me->cpu) > timeout) { | |
| 3124 _PR_IOQ_TIMEOUT(me->cpu) = timeout; | |
| 3125 } | |
| 3126 | |
| 3127 _PR_IOQ_OSFD_CNT(me->cpu) += pdcnt; | |
| 3128 | |
| 3129 _PR_SLEEPQ_LOCK(me->cpu); | |
| 3130 _PR_ADD_SLEEPQ(me, timeout); | |
| 3131 me->state = _PR_IO_WAIT; | |
| 3132 me->io_pending = PR_TRUE; | |
| 3133 me->io_suspended = PR_FALSE; | |
| 3134 _PR_SLEEPQ_UNLOCK(me->cpu); | |
| 3135 _PR_THREAD_UNLOCK(me); | |
| 3136 _PR_MD_IOQ_UNLOCK(); | |
| 3137 | |
| 3138 _PR_MD_WAIT(me, timeout); | |
| 3139 | |
| 3140 me->io_pending = PR_FALSE; | |
| 3141 me->io_suspended = PR_FALSE; | |
| 3142 | |
| 3143 /* | |
| 3144 * This thread should run on the same cpu on which it was blocked; when | |
| 3145 * the IO request times out the fd sets and fd counts for the | |
| 3146 * cpu are updated below. | |
| 3147 */ | |
| 3148 PR_ASSERT(me->cpu == io_cpu); | |
| 3149 | |
| 3150 /* | |
| 3151 ** If we timed out the pollq might still be on the ioq. Remove it | |
| 3152 ** before continuing. | |
| 3153 */ | |
| 3154 if (pq.on_ioq) { | |
| 3155 _PR_MD_IOQ_LOCK(); | |
| 3156 /* | |
| 3157 * Need to check pq.on_ioq again | |
| 3158 */ | |
| 3159 if (pq.on_ioq) { | |
| 3160 PR_REMOVE_LINK(&pq.links); | |
| 3161 #ifndef _PR_USE_POLL | |
| 3162 eunixpd = unixpds + pdcnt; | |
| 3163 for (unixpd = unixpds; unixpd < eunixpd; unixpd++) { | |
| 3164 PRInt32 osfd = unixpd->osfd; | |
| 3165 PRInt16 in_flags = unixpd->in_flags; | |
| 3166 | |
| 3167 if (in_flags & _PR_UNIX_POLL_READ) { | |
| 3168 if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) | |
| 3169 FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); | |
| 3170 } | |
| 3171 if (in_flags & _PR_UNIX_POLL_WRITE) { | |
| 3172 if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) | |
| 3173 FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); | |
| 3174 } | |
| 3175 if (in_flags & _PR_UNIX_POLL_EXCEPT) { | |
| 3176 if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) | |
| 3177 FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); | |
| 3178 } | |
| 3179 } | |
| 3180 #endif /* _PR_USE_POLL */ | |
| 3181 PR_ASSERT(pq.npds == pdcnt); | |
| 3182 _PR_IOQ_OSFD_CNT(me->cpu) -= pdcnt; | |
| 3183 PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0); | |
| 3184 } | |
| 3185 _PR_MD_IOQ_UNLOCK(); | |
| 3186 } | |
| 3187 /* XXX Should we use _PR_FAST_INTSON or _PR_INTSON? */ | |
| 3188 if (1 == pdcnt) { | |
| 3189 _PR_FAST_INTSON(is); | |
| 3190 } else { | |
| 3191 _PR_INTSON(is); | |
| 3192 } | |
| 3193 | |
| 3194 if (_PR_PENDING_INTERRUPT(me)) { | |
| 3195 me->flags &= ~_PR_INTERRUPT; | |
| 3196 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
| 3197 return -1; | |
| 3198 } | |
| 3199 | |
| 3200 rv = 0; | |
| 3201 if (pq.on_ioq == PR_FALSE) { | |
| 3202 /* Count the number of ready descriptors */ | |
| 3203 while (--pdcnt >= 0) { | |
| 3204 if (unixpds->out_flags != 0) { | |
| 3205 rv++; | |
| 3206 } | |
| 3207 unixpds++; | |
| 3208 } | |
| 3209 } | |
| 3210 | |
| 3211 return rv; | |
| 3212 } | |
| 3213 | |
| 3214 /* | |
| 3215 * Unblock threads waiting for I/O | |
| 3216 * used when interrupting threads | |
| 3217 * | |
| 3218 * NOTE: The thread lock should held when this function is called. | |
| 3219 * On return, the thread lock is released. | |
| 3220 */ | |
| 3221 void _PR_Unblock_IO_Wait(PRThread *thr) | |
| 3222 { | |
| 3223 int pri = thr->priority; | |
| 3224 _PRCPU *cpu = thr->cpu; | |
| 3225 | |
| 3226 /* | |
| 3227 * GLOBAL threads wakeup periodically to check for interrupt | |
| 3228 */ | |
| 3229 if (_PR_IS_NATIVE_THREAD(thr)) { | |
| 3230 _PR_THREAD_UNLOCK(thr); | |
| 3231 return; | |
| 3232 } | |
| 3233 | |
| 3234 PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ)); | |
| 3235 _PR_SLEEPQ_LOCK(cpu); | |
| 3236 _PR_DEL_SLEEPQ(thr, PR_TRUE); | |
| 3237 _PR_SLEEPQ_UNLOCK(cpu); | |
| 3238 | |
| 3239 PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD)); | |
| 3240 thr->state = _PR_RUNNABLE; | |
| 3241 _PR_RUNQ_LOCK(cpu); | |
| 3242 _PR_ADD_RUNQ(thr, cpu, pri); | |
| 3243 _PR_RUNQ_UNLOCK(cpu); | |
| 3244 _PR_THREAD_UNLOCK(thr); | |
| 3245 _PR_MD_WAKEUP_WAITER(thr); | |
| 3246 } | |
| 3247 #endif /* !defined(_PR_PTHREADS) */ | |
| 3248 | |
| 3249 /* | |
| 3250 * When a nonblocking connect has completed, determine whether it | |
| 3251 * succeeded or failed, and if it failed, what the error code is. | |
| 3252 * | |
| 3253 * The function returns the error code. An error code of 0 means | |
| 3254 * that the nonblocking connect succeeded. | |
| 3255 */ | |
| 3256 | |
| 3257 int _MD_unix_get_nonblocking_connect_error(int osfd) | |
| 3258 { | |
| 3259 #if defined(NTO) | |
| 3260 /* Neutrino does not support the SO_ERROR socket option */ | |
| 3261 PRInt32 rv; | |
| 3262 PRNetAddr addr; | |
| 3263 _PRSockLen_t addrlen = sizeof(addr); | |
| 3264 | |
| 3265 /* Test to see if we are using the Tiny TCP/IP Stack or the Full one. */ | |
| 3266 struct statvfs superblock; | |
| 3267 rv = fstatvfs(osfd, &superblock); | |
| 3268 if (rv == 0) { | |
| 3269 if (strcmp(superblock.f_basetype, "ttcpip") == 0) { | |
| 3270 /* Using the Tiny Stack! */ | |
| 3271 rv = getpeername(osfd, (struct sockaddr *) &addr, | |
| 3272 (_PRSockLen_t *) &addrlen); | |
| 3273 if (rv == -1) { | |
| 3274 int errno_copy = errno; /* make a copy so I don't | |
| 3275 * accidentally reset */ | |
| 3276 | |
| 3277 if (errno_copy == ENOTCONN) { | |
| 3278 struct stat StatInfo; | |
| 3279 rv = fstat(osfd, &StatInfo); | |
| 3280 if (rv == 0) { | |
| 3281 time_t current_time = time(NULL); | |
| 3282 | |
| 3283 /* | |
| 3284 * this is a real hack, can't explain why it | |
| 3285 * works it just does | |
| 3286 */ | |
| 3287 if (abs(current_time - StatInfo.st_atime) < 5) { | |
| 3288 return ECONNREFUSED; | |
| 3289 } else { | |
| 3290 return ETIMEDOUT; | |
| 3291 } | |
| 3292 } else { | |
| 3293 return ECONNREFUSED; | |
| 3294 } | |
| 3295 } else { | |
| 3296 return errno_copy; | |
| 3297 } | |
| 3298 } else { | |
| 3299 /* No Error */ | |
| 3300 return 0; | |
| 3301 } | |
| 3302 } else { | |
| 3303 /* Have the FULL Stack which supports SO_ERROR */ | |
| 3304 /* Hasn't been written yet, never been tested! */ | |
| 3305 /* Jerry.Kirk@Nexwarecorp.com */ | |
| 3306 | |
| 3307 int err; | |
| 3308 _PRSockLen_t optlen = sizeof(err); | |
| 3309 | |
| 3310 if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, | |
| 3311 (char *) &err, &optlen) == -1) { | |
| 3312 return errno; | |
| 3313 } else { | |
| 3314 return err; | |
| 3315 } | |
| 3316 } | |
| 3317 } else { | |
| 3318 return ECONNREFUSED; | |
| 3319 } | |
| 3320 #elif defined(UNIXWARE) | |
| 3321 /* | |
| 3322 * getsockopt() fails with EPIPE, so use getmsg() instead. | |
| 3323 */ | |
| 3324 | |
| 3325 int rv; | |
| 3326 int flags = 0; | |
| 3327 rv = getmsg(osfd, NULL, NULL, &flags); | |
| 3328 PR_ASSERT(-1 == rv || 0 == rv); | |
| 3329 if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) { | |
| 3330 return errno; | |
| 3331 } | |
| 3332 return 0; /* no error */ | |
| 3333 #else | |
| 3334 int err; | |
| 3335 _PRSockLen_t optlen = sizeof(err); | |
| 3336 if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) == -1) { | |
| 3337 return errno; | |
| 3338 } else { | |
| 3339 return err; | |
| 3340 } | |
| 3341 #endif | |
| 3342 } | |
| 3343 | |
| 3344 /************************************************************************/ | |
| 3345 | |
| 3346 /* | |
| 3347 ** Special hacks for xlib. Xlib/Xt/Xm is not re-entrant nor is it thread | |
| 3348 ** safe. Unfortunately, neither is mozilla. To make these programs work | |
| 3349 ** in a pre-emptive threaded environment, we need to use a lock. | |
| 3350 */ | |
| 3351 | |
| 3352 void PR_XLock(void) | |
| 3353 { | |
| 3354 PR_EnterMonitor(_pr_Xfe_mon); | |
| 3355 } | |
| 3356 | |
| 3357 void PR_XUnlock(void) | |
| 3358 { | |
| 3359 PR_ExitMonitor(_pr_Xfe_mon); | |
| 3360 } | |
| 3361 | |
| 3362 PRBool PR_XIsLocked(void) | |
| 3363 { | |
| 3364 return (PR_InMonitor(_pr_Xfe_mon)) ? PR_TRUE : PR_FALSE; | |
| 3365 } | |
| 3366 | |
| 3367 void PR_XWait(int ms) | |
| 3368 { | |
| 3369 PR_Wait(_pr_Xfe_mon, PR_MillisecondsToInterval(ms)); | |
| 3370 } | |
| 3371 | |
| 3372 void PR_XNotify(void) | |
| 3373 { | |
| 3374 PR_Notify(_pr_Xfe_mon); | |
| 3375 } | |
| 3376 | |
| 3377 void PR_XNotifyAll(void) | |
| 3378 { | |
| 3379 PR_NotifyAll(_pr_Xfe_mon); | |
| 3380 } | |
| 3381 | |
| 3382 #if defined(HAVE_FCNTL_FILE_LOCKING) | |
| 3383 | |
| 3384 PRStatus | |
| 3385 _MD_LockFile(PRInt32 f) | |
| 3386 { | |
| 3387 PRInt32 rv; | |
| 3388 struct flock arg; | |
| 3389 | |
| 3390 arg.l_type = F_WRLCK; | |
| 3391 arg.l_whence = SEEK_SET; | |
| 3392 arg.l_start = 0; | |
| 3393 arg.l_len = 0; /* until EOF */ | |
| 3394 rv = fcntl(f, F_SETLKW, &arg); | |
| 3395 if (rv == 0) | |
| 3396 return PR_SUCCESS; | |
| 3397 _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); | |
| 3398 return PR_FAILURE; | |
| 3399 } | |
| 3400 | |
| 3401 PRStatus | |
| 3402 _MD_TLockFile(PRInt32 f) | |
| 3403 { | |
| 3404 PRInt32 rv; | |
| 3405 struct flock arg; | |
| 3406 | |
| 3407 arg.l_type = F_WRLCK; | |
| 3408 arg.l_whence = SEEK_SET; | |
| 3409 arg.l_start = 0; | |
| 3410 arg.l_len = 0; /* until EOF */ | |
| 3411 rv = fcntl(f, F_SETLK, &arg); | |
| 3412 if (rv == 0) | |
| 3413 return PR_SUCCESS; | |
| 3414 _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); | |
| 3415 return PR_FAILURE; | |
| 3416 } | |
| 3417 | |
| 3418 PRStatus | |
| 3419 _MD_UnlockFile(PRInt32 f) | |
| 3420 { | |
| 3421 PRInt32 rv; | |
| 3422 struct flock arg; | |
| 3423 | |
| 3424 arg.l_type = F_UNLCK; | |
| 3425 arg.l_whence = SEEK_SET; | |
| 3426 arg.l_start = 0; | |
| 3427 arg.l_len = 0; /* until EOF */ | |
| 3428 rv = fcntl(f, F_SETLK, &arg); | |
| 3429 if (rv == 0) | |
| 3430 return PR_SUCCESS; | |
| 3431 _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); | |
| 3432 return PR_FAILURE; | |
| 3433 } | |
| 3434 | |
| 3435 #elif defined(HAVE_BSD_FLOCK) | |
| 3436 | |
| 3437 #include <sys/file.h> | |
| 3438 | |
| 3439 PRStatus | |
| 3440 _MD_LockFile(PRInt32 f) | |
| 3441 { | |
| 3442 PRInt32 rv; | |
| 3443 rv = flock(f, LOCK_EX); | |
| 3444 if (rv == 0) | |
| 3445 return PR_SUCCESS; | |
| 3446 _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); | |
| 3447 return PR_FAILURE; | |
| 3448 } | |
| 3449 | |
| 3450 PRStatus | |
| 3451 _MD_TLockFile(PRInt32 f) | |
| 3452 { | |
| 3453 PRInt32 rv; | |
| 3454 rv = flock(f, LOCK_EX|LOCK_NB); | |
| 3455 if (rv == 0) | |
| 3456 return PR_SUCCESS; | |
| 3457 _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); | |
| 3458 return PR_FAILURE; | |
| 3459 } | |
| 3460 | |
| 3461 PRStatus | |
| 3462 _MD_UnlockFile(PRInt32 f) | |
| 3463 { | |
| 3464 PRInt32 rv; | |
| 3465 rv = flock(f, LOCK_UN); | |
| 3466 if (rv == 0) | |
| 3467 return PR_SUCCESS; | |
| 3468 _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); | |
| 3469 return PR_FAILURE; | |
| 3470 } | |
| 3471 #else | |
| 3472 | |
| 3473 PRStatus | |
| 3474 _MD_LockFile(PRInt32 f) | |
| 3475 { | |
| 3476 PRInt32 rv; | |
| 3477 rv = lockf(f, F_LOCK, 0); | |
| 3478 if (rv == 0) | |
| 3479 return PR_SUCCESS; | |
| 3480 _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); | |
| 3481 return PR_FAILURE; | |
| 3482 } | |
| 3483 | |
| 3484 PRStatus | |
| 3485 _MD_TLockFile(PRInt32 f) | |
| 3486 { | |
| 3487 PRInt32 rv; | |
| 3488 rv = lockf(f, F_TLOCK, 0); | |
| 3489 if (rv == 0) | |
| 3490 return PR_SUCCESS; | |
| 3491 _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); | |
| 3492 return PR_FAILURE; | |
| 3493 } | |
| 3494 | |
| 3495 PRStatus | |
| 3496 _MD_UnlockFile(PRInt32 f) | |
| 3497 { | |
| 3498 PRInt32 rv; | |
| 3499 rv = lockf(f, F_ULOCK, 0); | |
| 3500 if (rv == 0) | |
| 3501 return PR_SUCCESS; | |
| 3502 _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); | |
| 3503 return PR_FAILURE; | |
| 3504 } | |
| 3505 #endif | |
| 3506 | |
| 3507 PRStatus _MD_gethostname(char *name, PRUint32 namelen) | |
| 3508 { | |
| 3509 PRIntn rv; | |
| 3510 | |
| 3511 rv = gethostname(name, namelen); | |
| 3512 if (0 == rv) { | |
| 3513 return PR_SUCCESS; | |
| 3514 } | |
| 3515 _PR_MD_MAP_GETHOSTNAME_ERROR(_MD_ERRNO()); | |
| 3516 return PR_FAILURE; | |
| 3517 } | |
| 3518 | |
| 3519 PRStatus _MD_getsysinfo(PRSysInfo cmd, char *name, PRUint32 namelen) | |
| 3520 { | |
| 3521 struct utsname info; | |
| 3522 | |
| 3523 PR_ASSERT((cmd == PR_SI_SYSNAME) || (cmd == PR_SI_RELEASE)); | |
| 3524 | |
| 3525 if (uname(&info) == -1) { | |
| 3526 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
| 3527 return PR_FAILURE; | |
| 3528 } | |
| 3529 if (PR_SI_SYSNAME == cmd) | |
| 3530 (void)PR_snprintf(name, namelen, info.sysname); | |
| 3531 else if (PR_SI_RELEASE == cmd) | |
| 3532 (void)PR_snprintf(name, namelen, info.release); | |
| 3533 else | |
| 3534 return PR_FAILURE; | |
| 3535 return PR_SUCCESS; | |
| 3536 } | |
| 3537 | |
| 3538 /* | |
| 3539 ******************************************************************* | |
| 3540 * | |
| 3541 * Memory-mapped files | |
| 3542 * | |
| 3543 ******************************************************************* | |
| 3544 */ | |
| 3545 | |
| 3546 PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) | |
| 3547 { | |
| 3548 PRFileInfo info; | |
| 3549 PRUint32 sz; | |
| 3550 | |
| 3551 LL_L2UI(sz, size); | |
| 3552 if (sz) { | |
| 3553 if (PR_GetOpenFileInfo(fmap->fd, &info) == PR_FAILURE) { | |
| 3554 return PR_FAILURE; | |
| 3555 } | |
| 3556 if (sz > info.size) { | |
| 3557 /* | |
| 3558 * Need to extend the file | |
| 3559 */ | |
| 3560 if (fmap->prot != PR_PROT_READWRITE) { | |
| 3561 PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0); | |
| 3562 return PR_FAILURE; | |
| 3563 } | |
| 3564 if (PR_Seek(fmap->fd, sz - 1, PR_SEEK_SET) == -1) { | |
| 3565 return PR_FAILURE; | |
| 3566 } | |
| 3567 if (PR_Write(fmap->fd, "", 1) != 1) { | |
| 3568 return PR_FAILURE; | |
| 3569 } | |
| 3570 } | |
| 3571 } | |
| 3572 if (fmap->prot == PR_PROT_READONLY) { | |
| 3573 fmap->md.prot = PROT_READ; | |
| 3574 #ifdef OSF1V4_MAP_PRIVATE_BUG | |
| 3575 /* | |
| 3576 * Use MAP_SHARED to work around a bug in OSF1 V4.0D | |
| 3577 * (QAR 70220 in the OSF_QAR database) that results in | |
| 3578 * corrupted data in the memory-mapped region. This | |
| 3579 * bug is fixed in V5.0. | |
| 3580 */ | |
| 3581 fmap->md.flags = MAP_SHARED; | |
| 3582 #else | |
| 3583 fmap->md.flags = MAP_PRIVATE; | |
| 3584 #endif | |
| 3585 } else if (fmap->prot == PR_PROT_READWRITE) { | |
| 3586 fmap->md.prot = PROT_READ | PROT_WRITE; | |
| 3587 fmap->md.flags = MAP_SHARED; | |
| 3588 } else { | |
| 3589 PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY); | |
| 3590 fmap->md.prot = PROT_READ | PROT_WRITE; | |
| 3591 fmap->md.flags = MAP_PRIVATE; | |
| 3592 } | |
| 3593 return PR_SUCCESS; | |
| 3594 } | |
| 3595 | |
| 3596 void * _MD_MemMap( | |
| 3597 PRFileMap *fmap, | |
| 3598 PRInt64 offset, | |
| 3599 PRUint32 len) | |
| 3600 { | |
| 3601 PRInt32 off; | |
| 3602 void *addr; | |
| 3603 | |
| 3604 LL_L2I(off, offset); | |
| 3605 if ((addr = mmap(0, len, fmap->md.prot, fmap->md.flags, | |
| 3606 fmap->fd->secret->md.osfd, off)) == (void *) -1) { | |
| 3607 _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO()); | |
| 3608 addr = NULL; | |
| 3609 } | |
| 3610 return addr; | |
| 3611 } | |
| 3612 | |
| 3613 PRStatus _MD_MemUnmap(void *addr, PRUint32 len) | |
| 3614 { | |
| 3615 if (munmap(addr, len) == 0) { | |
| 3616 return PR_SUCCESS; | |
| 3617 } else { | |
| 3618 if (errno == EINVAL) { | |
| 3619 PR_SetError(PR_INVALID_ARGUMENT_ERROR, errno); | |
| 3620 } else { | |
| 3621 PR_SetError(PR_UNKNOWN_ERROR, errno); | |
| 3622 } | |
| 3623 return PR_FAILURE; | |
| 3624 } | |
| 3625 } | |
| 3626 | |
| 3627 PRStatus _MD_CloseFileMap(PRFileMap *fmap) | |
| 3628 { | |
| 3629 if ( PR_TRUE == fmap->md.isAnonFM ) { | |
| 3630 PRStatus rc = PR_Close( fmap->fd ); | |
| 3631 if ( PR_FAILURE == rc ) { | |
| 3632 PR_LOG( _pr_io_lm, PR_LOG_DEBUG, | |
| 3633 ("_MD_CloseFileMap(): error closing anonymnous file map osfd")); | |
| 3634 return PR_FAILURE; | |
| 3635 } | |
| 3636 } | |
| 3637 PR_DELETE(fmap); | |
| 3638 return PR_SUCCESS; | |
| 3639 } | |
| 3640 | |
| 3641 #if defined(_PR_NEED_FAKE_POLL) | |
| 3642 | |
| 3643 /* | |
| 3644 * Some platforms don't have poll(). For easier porting of code | |
| 3645 * that calls poll(), we emulate poll() using select(). | |
| 3646 */ | |
| 3647 | |
| 3648 int poll(struct pollfd *filedes, unsigned long nfds, int timeout) | |
| 3649 { | |
| 3650 int i; | |
| 3651 int rv; | |
| 3652 int maxfd; | |
| 3653 fd_set rd, wr, ex; | |
| 3654 struct timeval tv, *tvp; | |
| 3655 | |
| 3656 if (timeout < 0 && timeout != -1) { | |
| 3657 errno = EINVAL; | |
| 3658 return -1; | |
| 3659 } | |
| 3660 | |
| 3661 if (timeout == -1) { | |
| 3662 tvp = NULL; | |
| 3663 } else { | |
| 3664 tv.tv_sec = timeout / 1000; | |
| 3665 tv.tv_usec = (timeout % 1000) * 1000; | |
| 3666 tvp = &tv; | |
| 3667 } | |
| 3668 | |
| 3669 maxfd = -1; | |
| 3670 FD_ZERO(&rd); | |
| 3671 FD_ZERO(&wr); | |
| 3672 FD_ZERO(&ex); | |
| 3673 | |
| 3674 for (i = 0; i < nfds; i++) { | |
| 3675 int osfd = filedes[i].fd; | |
| 3676 int events = filedes[i].events; | |
| 3677 PRBool fdHasEvent = PR_FALSE; | |
| 3678 | |
| 3679 if (osfd < 0) { | |
| 3680 continue; /* Skip this osfd. */ | |
| 3681 } | |
| 3682 | |
| 3683 /* | |
| 3684 * Map the poll events to the select fd_sets. | |
| 3685 * POLLIN, POLLRDNORM ===> readable | |
| 3686 * POLLOUT, POLLWRNORM ===> writable | |
| 3687 * POLLPRI, POLLRDBAND ===> exception | |
| 3688 * POLLNORM, POLLWRBAND (and POLLMSG on some platforms) | |
| 3689 * are ignored. | |
| 3690 * | |
| 3691 * The output events POLLERR and POLLHUP are never turned on. | |
| 3692 * POLLNVAL may be turned on. | |
| 3693 */ | |
| 3694 | |
| 3695 if (events & (POLLIN | POLLRDNORM)) { | |
| 3696 FD_SET(osfd, &rd); | |
| 3697 fdHasEvent = PR_TRUE; | |
| 3698 } | |
| 3699 if (events & (POLLOUT | POLLWRNORM)) { | |
| 3700 FD_SET(osfd, &wr); | |
| 3701 fdHasEvent = PR_TRUE; | |
| 3702 } | |
| 3703 if (events & (POLLPRI | POLLRDBAND)) { | |
| 3704 FD_SET(osfd, &ex); | |
| 3705 fdHasEvent = PR_TRUE; | |
| 3706 } | |
| 3707 if (fdHasEvent && osfd > maxfd) { | |
| 3708 maxfd = osfd; | |
| 3709 } | |
| 3710 } | |
| 3711 | |
| 3712 rv = select(maxfd + 1, &rd, &wr, &ex, tvp); | |
| 3713 | |
| 3714 /* Compute poll results */ | |
| 3715 if (rv > 0) { | |
| 3716 rv = 0; | |
| 3717 for (i = 0; i < nfds; i++) { | |
| 3718 PRBool fdHasEvent = PR_FALSE; | |
| 3719 | |
| 3720 filedes[i].revents = 0; | |
| 3721 if (filedes[i].fd < 0) { | |
| 3722 continue; | |
| 3723 } | |
| 3724 if (FD_ISSET(filedes[i].fd, &rd)) { | |
| 3725 if (filedes[i].events & POLLIN) { | |
| 3726 filedes[i].revents |= POLLIN; | |
| 3727 } | |
| 3728 if (filedes[i].events & POLLRDNORM) { | |
| 3729 filedes[i].revents |= POLLRDNORM; | |
| 3730 } | |
| 3731 fdHasEvent = PR_TRUE; | |
| 3732 } | |
| 3733 if (FD_ISSET(filedes[i].fd, &wr)) { | |
| 3734 if (filedes[i].events & POLLOUT) { | |
| 3735 filedes[i].revents |= POLLOUT; | |
| 3736 } | |
| 3737 if (filedes[i].events & POLLWRNORM) { | |
| 3738 filedes[i].revents |= POLLWRNORM; | |
| 3739 } | |
| 3740 fdHasEvent = PR_TRUE; | |
| 3741 } | |
| 3742 if (FD_ISSET(filedes[i].fd, &ex)) { | |
| 3743 if (filedes[i].events & POLLPRI) { | |
| 3744 filedes[i].revents |= POLLPRI; | |
| 3745 } | |
| 3746 if (filedes[i].events & POLLRDBAND) { | |
| 3747 filedes[i].revents |= POLLRDBAND; | |
| 3748 } | |
| 3749 fdHasEvent = PR_TRUE; | |
| 3750 } | |
| 3751 if (fdHasEvent) { | |
| 3752 rv++; | |
| 3753 } | |
| 3754 } | |
| 3755 PR_ASSERT(rv > 0); | |
| 3756 } else if (rv == -1 && errno == EBADF) { | |
| 3757 rv = 0; | |
| 3758 for (i = 0; i < nfds; i++) { | |
| 3759 filedes[i].revents = 0; | |
| 3760 if (filedes[i].fd < 0) { | |
| 3761 continue; | |
| 3762 } | |
| 3763 if (fcntl(filedes[i].fd, F_GETFL, 0) == -1) { | |
| 3764 filedes[i].revents = POLLNVAL; | |
| 3765 rv++; | |
| 3766 } | |
| 3767 } | |
| 3768 PR_ASSERT(rv > 0); | |
| 3769 } | |
| 3770 PR_ASSERT(-1 != timeout || rv != 0); | |
| 3771 | |
| 3772 return rv; | |
| 3773 } | |
| 3774 #endif /* _PR_NEED_FAKE_POLL */ | |
| OLD | NEW |