Coverage Report

Created: 2026-08-18 06:34

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