1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Platform specific code for Linux goes here. For the POSIX comaptible parts
29// the implementation is in platform-posix.cc.
30
31#include <pthread.h>
32#include <semaphore.h>
33#include <signal.h>
34#include <sys/prctl.h>
35#include <sys/time.h>
36#include <sys/resource.h>
37#include <sys/syscall.h>
38#include <sys/types.h>
39#include <stdlib.h>
40
41#if defined(__GLIBC__) && !defined(__UCLIBC__)
42#include <execinfo.h>
43#include <cxxabi.h>
44#endif
45
46// Ubuntu Dapper requires memory pages to be marked as
47// executable. Otherwise, OS raises an exception when executing code
48// in that page.
49#include <sys/types.h>  // mmap & munmap
50#include <sys/mman.h>   // mmap & munmap
51#include <sys/stat.h>   // open
52#include <fcntl.h>      // open
53#include <unistd.h>     // sysconf
54#include <strings.h>    // index
55#include <errno.h>
56#include <stdarg.h>
57
58// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
59// Old versions of the C library <signal.h> didn't define the type.
60#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
61    defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
62#include <asm/sigcontext.h>
63#endif
64
65#undef MAP_TYPE
66
67#include "v8.h"
68
69#include "platform-posix.h"
70#include "platform.h"
71#include "v8threads.h"
72#include "vm-state-inl.h"
73
74
75namespace v8 {
76namespace internal {
77
78
79static Mutex* limit_mutex = NULL;
80
81
82#ifdef __arm__
83static bool CPUInfoContainsString(const char * search_string) {
84  const char* file_name = "/proc/cpuinfo";
85  // This is written as a straight shot one pass parser
86  // and not using STL string and ifstream because,
87  // on Linux, it's reading from a (non-mmap-able)
88  // character special device.
89  FILE* f = NULL;
90  const char* what = search_string;
91
92  if (NULL == (f = fopen(file_name, "r"))) {
93    OS::PrintError("Failed to open /proc/cpuinfo\n");
94    return false;
95  }
96
97  int k;
98  while (EOF != (k = fgetc(f))) {
99    if (k == *what) {
100      ++what;
101      while ((*what != '\0') && (*what == fgetc(f))) {
102        ++what;
103      }
104      if (*what == '\0') {
105        fclose(f);
106        return true;
107      } else {
108        what = search_string;
109      }
110    }
111  }
112  fclose(f);
113
114  // Did not find string in the proc file.
115  return false;
116}
117
118
119bool OS::ArmCpuHasFeature(CpuFeature feature) {
120  const char* search_string = NULL;
121  // Simple detection of VFP at runtime for Linux.
122  // It is based on /proc/cpuinfo, which reveals hardware configuration
123  // to user-space applications.  According to ARM (mid 2009), no similar
124  // facility is universally available on the ARM architectures,
125  // so it's up to individual OSes to provide such.
126  switch (feature) {
127    case VFP3:
128      search_string = "vfpv3";
129      break;
130    case NEON:
131      search_string = "neon";
132      break;
133    case ARMv7:
134      search_string = "ARMv7";
135      break;
136    case SUDIV:
137      search_string = "idiva";
138      break;
139    case VFP32DREGS:
140      // This case is handled specially below.
141      break;
142    default:
143      UNREACHABLE();
144  }
145
146  if (feature == VFP32DREGS) {
147    return ArmCpuHasFeature(VFP3) && !CPUInfoContainsString("d16");
148  }
149
150  if (CPUInfoContainsString(search_string)) {
151    return true;
152  }
153
154  if (feature == VFP3) {
155    // Some old kernels will report vfp not vfpv3. Here we make a last attempt
156    // to detect vfpv3 by checking for vfp *and* neon, since neon is only
157    // available on architectures with vfpv3.
158    // Checking neon on its own is not enough as it is possible to have neon
159    // without vfp.
160    if (CPUInfoContainsString("vfp") && CPUInfoContainsString("neon")) {
161      return true;
162    }
163  }
164
165  return false;
166}
167
168
169CpuImplementer OS::GetCpuImplementer() {
170  static bool use_cached_value = false;
171  static CpuImplementer cached_value = UNKNOWN_IMPLEMENTER;
172  if (use_cached_value) {
173    return cached_value;
174  }
175  if (CPUInfoContainsString("CPU implementer\t: 0x41")) {
176    cached_value = ARM_IMPLEMENTER;
177  } else if (CPUInfoContainsString("CPU implementer\t: 0x51")) {
178    cached_value = QUALCOMM_IMPLEMENTER;
179  } else {
180    cached_value = UNKNOWN_IMPLEMENTER;
181  }
182  use_cached_value = true;
183  return cached_value;
184}
185
186
187CpuPart OS::GetCpuPart(CpuImplementer implementer) {
188  static bool use_cached_value = false;
189  static CpuPart cached_value = CPU_UNKNOWN;
190  if (use_cached_value) {
191    return cached_value;
192  }
193  if (implementer == ARM_IMPLEMENTER) {
194    if (CPUInfoContainsString("CPU part\t: 0xc0f")) {
195      cached_value = CORTEX_A15;
196    } else if (CPUInfoContainsString("CPU part\t: 0xc0c")) {
197      cached_value = CORTEX_A12;
198    } else if (CPUInfoContainsString("CPU part\t: 0xc09")) {
199      cached_value = CORTEX_A9;
200    } else if (CPUInfoContainsString("CPU part\t: 0xc08")) {
201      cached_value = CORTEX_A8;
202    } else if (CPUInfoContainsString("CPU part\t: 0xc07")) {
203      cached_value = CORTEX_A7;
204    } else if (CPUInfoContainsString("CPU part\t: 0xc05")) {
205      cached_value = CORTEX_A5;
206    } else {
207      cached_value = CPU_UNKNOWN;
208    }
209  } else {
210    cached_value = CPU_UNKNOWN;
211  }
212  use_cached_value = true;
213  return cached_value;
214}
215
216
217bool OS::ArmUsingHardFloat() {
218  // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
219  // the Floating Point ABI used (PCS stands for Procedure Call Standard).
220  // We use these as well as a couple of other defines to statically determine
221  // what FP ABI used.
222  // GCC versions 4.4 and below don't support hard-fp.
223  // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
224  // __ARM_PCS_VFP.
225
226#define GCC_VERSION (__GNUC__ * 10000                                          \
227                     + __GNUC_MINOR__ * 100                                    \
228                     + __GNUC_PATCHLEVEL__)
229#if GCC_VERSION >= 40600
230#if defined(__ARM_PCS_VFP)
231  return true;
232#else
233  return false;
234#endif
235
236#elif GCC_VERSION < 40500
237  return false;
238
239#else
240#if defined(__ARM_PCS_VFP)
241  return true;
242#elif defined(__ARM_PCS) || defined(__SOFTFP__) || defined(__SOFTFP) || \
243      !defined(__VFP_FP__)
244  return false;
245#else
246#error "Your version of GCC does not report the FP ABI compiled for."          \
247       "Please report it on this issue"                                        \
248       "http://code.google.com/p/v8/issues/detail?id=2140"
249
250#endif
251#endif
252#undef GCC_VERSION
253}
254
255#endif  // def __arm__
256
257
258#ifdef __mips__
259bool OS::MipsCpuHasFeature(CpuFeature feature) {
260  const char* search_string = NULL;
261  const char* file_name = "/proc/cpuinfo";
262  // Simple detection of FPU at runtime for Linux.
263  // It is based on /proc/cpuinfo, which reveals hardware configuration
264  // to user-space applications.  According to MIPS (early 2010), no similar
265  // facility is universally available on the MIPS architectures,
266  // so it's up to individual OSes to provide such.
267  //
268  // This is written as a straight shot one pass parser
269  // and not using STL string and ifstream because,
270  // on Linux, it's reading from a (non-mmap-able)
271  // character special device.
272
273  switch (feature) {
274    case FPU:
275      search_string = "FPU";
276      break;
277    default:
278      UNREACHABLE();
279  }
280
281  FILE* f = NULL;
282  const char* what = search_string;
283
284  if (NULL == (f = fopen(file_name, "r"))) {
285    OS::PrintError("Failed to open /proc/cpuinfo\n");
286    return false;
287  }
288
289  int k;
290  while (EOF != (k = fgetc(f))) {
291    if (k == *what) {
292      ++what;
293      while ((*what != '\0') && (*what == fgetc(f))) {
294        ++what;
295      }
296      if (*what == '\0') {
297        fclose(f);
298        return true;
299      } else {
300        what = search_string;
301      }
302    }
303  }
304  fclose(f);
305
306  // Did not find string in the proc file.
307  return false;
308}
309#endif  // def __mips__
310
311
312const char* OS::LocalTimezone(double time) {
313  if (std::isnan(time)) return "";
314  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
315  struct tm* t = localtime(&tv);
316  if (NULL == t) return "";
317  return t->tm_zone;
318}
319
320
321double OS::LocalTimeOffset() {
322  time_t tv = time(NULL);
323  struct tm* t = localtime(&tv);
324  // tm_gmtoff includes any daylight savings offset, so subtract it.
325  return static_cast<double>(t->tm_gmtoff * msPerSecond -
326                             (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
327}
328
329
330// We keep the lowest and highest addresses mapped as a quick way of
331// determining that pointers are outside the heap (used mostly in assertions
332// and verification).  The estimate is conservative, i.e., not all addresses in
333// 'allocated' space are actually allocated to our heap.  The range is
334// [lowest, highest), inclusive on the low and and exclusive on the high end.
335static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
336static void* highest_ever_allocated = reinterpret_cast<void*>(0);
337
338
339static void UpdateAllocatedSpaceLimits(void* address, int size) {
340  ASSERT(limit_mutex != NULL);
341  ScopedLock lock(limit_mutex);
342
343  lowest_ever_allocated = Min(lowest_ever_allocated, address);
344  highest_ever_allocated =
345      Max(highest_ever_allocated,
346          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
347}
348
349
350bool OS::IsOutsideAllocatedSpace(void* address) {
351  return address < lowest_ever_allocated || address >= highest_ever_allocated;
352}
353
354
355void* OS::Allocate(const size_t requested,
356                   size_t* allocated,
357                   bool is_executable) {
358  const size_t msize = RoundUp(requested, AllocateAlignment());
359  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
360  void* addr = OS::GetRandomMmapAddr();
361  void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
362  if (mbase == MAP_FAILED) {
363    LOG(i::Isolate::Current(),
364        StringEvent("OS::Allocate", "mmap failed"));
365    return NULL;
366  }
367  *allocated = msize;
368  UpdateAllocatedSpaceLimits(mbase, msize);
369  return mbase;
370}
371
372
373void OS::DumpBacktrace() {
374  // backtrace is a glibc extension.
375#if defined(__GLIBC__) && !defined(__UCLIBC__)
376  POSIXBacktraceHelper<backtrace, backtrace_symbols>::DumpBacktrace();
377#endif
378}
379
380
381class PosixMemoryMappedFile : public OS::MemoryMappedFile {
382 public:
383  PosixMemoryMappedFile(FILE* file, void* memory, int size)
384    : file_(file), memory_(memory), size_(size) { }
385  virtual ~PosixMemoryMappedFile();
386  virtual void* memory() { return memory_; }
387  virtual int size() { return size_; }
388 private:
389  FILE* file_;
390  void* memory_;
391  int size_;
392};
393
394
395OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
396  FILE* file = fopen(name, "r+");
397  if (file == NULL) return NULL;
398
399  fseek(file, 0, SEEK_END);
400  int size = ftell(file);
401
402  void* memory =
403      mmap(OS::GetRandomMmapAddr(),
404           size,
405           PROT_READ | PROT_WRITE,
406           MAP_SHARED,
407           fileno(file),
408           0);
409  return new PosixMemoryMappedFile(file, memory, size);
410}
411
412
413OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
414    void* initial) {
415  FILE* file = fopen(name, "w+");
416  if (file == NULL) return NULL;
417  int result = fwrite(initial, size, 1, file);
418  if (result < 1) {
419    fclose(file);
420    return NULL;
421  }
422  void* memory =
423      mmap(OS::GetRandomMmapAddr(),
424           size,
425           PROT_READ | PROT_WRITE,
426           MAP_SHARED,
427           fileno(file),
428           0);
429  return new PosixMemoryMappedFile(file, memory, size);
430}
431
432
433PosixMemoryMappedFile::~PosixMemoryMappedFile() {
434  if (memory_) OS::Free(memory_, size_);
435  fclose(file_);
436}
437
438
439void OS::LogSharedLibraryAddresses() {
440  // This function assumes that the layout of the file is as follows:
441  // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
442  // If we encounter an unexpected situation we abort scanning further entries.
443  FILE* fp = fopen("/proc/self/maps", "r");
444  if (fp == NULL) return;
445
446  // Allocate enough room to be able to store a full file name.
447  const int kLibNameLen = FILENAME_MAX + 1;
448  char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
449
450  i::Isolate* isolate = ISOLATE;
451  // This loop will terminate once the scanning hits an EOF.
452  while (true) {
453    uintptr_t start, end;
454    char attr_r, attr_w, attr_x, attr_p;
455    // Parse the addresses and permission bits at the beginning of the line.
456    if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
457    if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
458
459    int c;
460    if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
461      // Found a read-only executable entry. Skip characters until we reach
462      // the beginning of the filename or the end of the line.
463      do {
464        c = getc(fp);
465      } while ((c != EOF) && (c != '\n') && (c != '/') && (c != '['));
466      if (c == EOF) break;  // EOF: Was unexpected, just exit.
467
468      // Process the filename if found.
469      if ((c == '/') || (c == '[')) {
470        // Push the '/' or '[' back into the stream to be read below.
471        ungetc(c, fp);
472
473        // Read to the end of the line. Exit if the read fails.
474        if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
475
476        // Drop the newline character read by fgets. We do not need to check
477        // for a zero-length string because we know that we at least read the
478        // '/' or '[' character.
479        lib_name[strlen(lib_name) - 1] = '\0';
480      } else {
481        // No library name found, just record the raw address range.
482        snprintf(lib_name, kLibNameLen,
483                 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
484      }
485      LOG(isolate, SharedLibraryEvent(lib_name, start, end));
486    } else {
487      // Entry not describing executable data. Skip to end of line to set up
488      // reading the next entry.
489      do {
490        c = getc(fp);
491      } while ((c != EOF) && (c != '\n'));
492      if (c == EOF) break;
493    }
494  }
495  free(lib_name);
496  fclose(fp);
497}
498
499
500void OS::SignalCodeMovingGC() {
501  // Support for ll_prof.py.
502  //
503  // The Linux profiler built into the kernel logs all mmap's with
504  // PROT_EXEC so that analysis tools can properly attribute ticks. We
505  // do a mmap with a name known by ll_prof.py and immediately munmap
506  // it. This injects a GC marker into the stream of events generated
507  // by the kernel and allows us to synchronize V8 code log and the
508  // kernel log.
509  int size = sysconf(_SC_PAGESIZE);
510  FILE* f = fopen(FLAG_gc_fake_mmap, "w+");
511  if (f == NULL) {
512    OS::PrintError("Failed to open %s\n", FLAG_gc_fake_mmap);
513    OS::Abort();
514  }
515  void* addr = mmap(OS::GetRandomMmapAddr(),
516                    size,
517#if defined(__native_client__)
518                    // The Native Client port of V8 uses an interpreter,
519                    // so code pages don't need PROT_EXEC.
520                    PROT_READ,
521#else
522                    PROT_READ | PROT_EXEC,
523#endif
524                    MAP_PRIVATE,
525                    fileno(f),
526                    0);
527  ASSERT(addr != MAP_FAILED);
528  OS::Free(addr, size);
529  fclose(f);
530}
531
532
533int OS::StackWalk(Vector<OS::StackFrame> frames) {
534  // backtrace is a glibc extension.
535#if defined(__GLIBC__) && !defined(__UCLIBC__)
536  return POSIXBacktraceHelper<backtrace, backtrace_symbols>::StackWalk(frames);
537#else
538  return 0;
539#endif
540}
541
542
543// Constants used for mmap.
544static const int kMmapFd = -1;
545static const int kMmapFdOffset = 0;
546
547
548VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
549
550
551VirtualMemory::VirtualMemory(size_t size)
552    : address_(ReserveRegion(size)), size_(size) { }
553
554
555VirtualMemory::VirtualMemory(size_t size, size_t alignment)
556    : address_(NULL), size_(0) {
557  ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
558  size_t request_size = RoundUp(size + alignment,
559                                static_cast<intptr_t>(OS::AllocateAlignment()));
560  void* reservation = mmap(OS::GetRandomMmapAddr(),
561                           request_size,
562                           PROT_NONE,
563                           MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
564                           kMmapFd,
565                           kMmapFdOffset);
566  if (reservation == MAP_FAILED) return;
567
568  Address base = static_cast<Address>(reservation);
569  Address aligned_base = RoundUp(base, alignment);
570  ASSERT_LE(base, aligned_base);
571
572  // Unmap extra memory reserved before and after the desired block.
573  if (aligned_base != base) {
574    size_t prefix_size = static_cast<size_t>(aligned_base - base);
575    OS::Free(base, prefix_size);
576    request_size -= prefix_size;
577  }
578
579  size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
580  ASSERT_LE(aligned_size, request_size);
581
582  if (aligned_size != request_size) {
583    size_t suffix_size = request_size - aligned_size;
584    OS::Free(aligned_base + aligned_size, suffix_size);
585    request_size -= suffix_size;
586  }
587
588  ASSERT(aligned_size == request_size);
589
590  address_ = static_cast<void*>(aligned_base);
591  size_ = aligned_size;
592}
593
594
595VirtualMemory::~VirtualMemory() {
596  if (IsReserved()) {
597    bool result = ReleaseRegion(address(), size());
598    ASSERT(result);
599    USE(result);
600  }
601}
602
603
604bool VirtualMemory::IsReserved() {
605  return address_ != NULL;
606}
607
608
609void VirtualMemory::Reset() {
610  address_ = NULL;
611  size_ = 0;
612}
613
614
615bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
616  return CommitRegion(address, size, is_executable);
617}
618
619
620bool VirtualMemory::Uncommit(void* address, size_t size) {
621  return UncommitRegion(address, size);
622}
623
624
625bool VirtualMemory::Guard(void* address) {
626  OS::Guard(address, OS::CommitPageSize());
627  return true;
628}
629
630
631void* VirtualMemory::ReserveRegion(size_t size) {
632  void* result = mmap(OS::GetRandomMmapAddr(),
633                      size,
634                      PROT_NONE,
635                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
636                      kMmapFd,
637                      kMmapFdOffset);
638
639  if (result == MAP_FAILED) return NULL;
640
641  return result;
642}
643
644
645bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
646#if defined(__native_client__)
647  // The Native Client port of V8 uses an interpreter,
648  // so code pages don't need PROT_EXEC.
649  int prot = PROT_READ | PROT_WRITE;
650#else
651  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
652#endif
653  if (MAP_FAILED == mmap(base,
654                         size,
655                         prot,
656                         MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
657                         kMmapFd,
658                         kMmapFdOffset)) {
659    return false;
660  }
661
662  UpdateAllocatedSpaceLimits(base, size);
663  return true;
664}
665
666
667bool VirtualMemory::UncommitRegion(void* base, size_t size) {
668  return mmap(base,
669              size,
670              PROT_NONE,
671              MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
672              kMmapFd,
673              kMmapFdOffset) != MAP_FAILED;
674}
675
676
677bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
678  return munmap(base, size) == 0;
679}
680
681
682bool VirtualMemory::HasLazyCommits() {
683  return true;
684}
685
686
687class LinuxSemaphore : public Semaphore {
688 public:
689  explicit LinuxSemaphore(int count) {  sem_init(&sem_, 0, count); }
690  virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
691
692  virtual void Wait();
693  virtual bool Wait(int timeout);
694  virtual void Signal() { sem_post(&sem_); }
695 private:
696  sem_t sem_;
697};
698
699
700void LinuxSemaphore::Wait() {
701  while (true) {
702    int result = sem_wait(&sem_);
703    if (result == 0) return;  // Successfully got semaphore.
704    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
705  }
706}
707
708
709#ifndef TIMEVAL_TO_TIMESPEC
710#define TIMEVAL_TO_TIMESPEC(tv, ts) do {                            \
711    (ts)->tv_sec = (tv)->tv_sec;                                    \
712    (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
713} while (false)
714#endif
715
716
717bool LinuxSemaphore::Wait(int timeout) {
718  const long kOneSecondMicros = 1000000;  // NOLINT
719
720  // Split timeout into second and nanosecond parts.
721  struct timeval delta;
722  delta.tv_usec = timeout % kOneSecondMicros;
723  delta.tv_sec = timeout / kOneSecondMicros;
724
725  struct timeval current_time;
726  // Get the current time.
727  if (gettimeofday(&current_time, NULL) == -1) {
728    return false;
729  }
730
731  // Calculate time for end of timeout.
732  struct timeval end_time;
733  timeradd(&current_time, &delta, &end_time);
734
735  struct timespec ts;
736  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
737  // Wait for semaphore signalled or timeout.
738  while (true) {
739    int result = sem_timedwait(&sem_, &ts);
740    if (result == 0) return true;  // Successfully got semaphore.
741    if (result > 0) {
742      // For glibc prior to 2.3.4 sem_timedwait returns the error instead of -1.
743      errno = result;
744      result = -1;
745    }
746    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
747    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
748  }
749}
750
751
752Semaphore* OS::CreateSemaphore(int count) {
753  return new LinuxSemaphore(count);
754}
755
756
757void OS::SetUp() {
758  // Seed the random number generator. We preserve microsecond resolution.
759  uint64_t seed = Ticks() ^ (getpid() << 16);
760  srandom(static_cast<unsigned int>(seed));
761  limit_mutex = CreateMutex();
762}
763
764
765void OS::TearDown() {
766  delete limit_mutex;
767}
768
769
770} }  // namespace v8::internal
771