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