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