[V8] QNX: Initialize mutex in SignalSender
[qt:qtjsbackend.git] / src / 3rdparty / v8 / src / platform-qnx.cc
1 // Copyright 2012 Research in Motion. 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 QNX 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/time.h>
35 #include <sys/resource.h>
36 #include <sys/types.h>
37 #include <stdlib.h>
38 #include <ucontext.h>
39 #include <backtrace.h>
40
41 // QNX requires memory pages to be marked as
42 // executable. Otherwise, OS raises an exception when executing code
43 // in that page.
44 #include <sys/types.h>  // mmap & munmap
45 #include <sys/mman.h>   // mmap & munmap
46 #include <sys/stat.h>   // open
47 #include <fcntl.h>      // open
48 #include <unistd.h>     // sysconf
49 #include <strings.h>    // index
50 #include <errno.h>
51 #include <stdarg.h>
52 #include <sys/procfs.h>
53 #include <sys/syspage.h>
54
55 #undef MAP_TYPE
56
57 #include "v8.h"
58
59 #include "platform.h"
60 #include "platform-posix.h"
61 #include "v8threads.h"
62 #include "vm-state-inl.h"
63
64
65 namespace v8 {
66 namespace internal {
67
68 // 0 is never a valid thread id on QNX since tids and pids share a
69 // name space and pid 0 is reserved (see man 2 kill).
70 static const pthread_t kNoThread = (pthread_t) 0;
71
72
73 double ceiling(double x) {
74   return ceil(x);
75 }
76
77
78 static Mutex* limit_mutex = NULL;
79
80
81 void OS::PostSetUp() {
82   POSIXPostSetUp();
83 }
84
85
86 uint64_t OS::CpuFeaturesImpliedByPlatform() {
87   return 0;  // QNX runs on anything.
88 }
89
90
91 #ifdef __arm__
92 static bool CPUInfoContainsString(const char * search_string) {
93   const char* file_name = "/proc/cpuinfo";
94   // This is written as a straight shot one pass parser
95   // and not using STL string and ifstream because,
96   // on QNX, it's reading from a (non-mmap-able)
97   // character special device.
98   FILE* f = NULL;
99   const char* what = search_string;
100
101   if (NULL == (f = fopen(file_name, "r")))
102     return false;
103
104   int k;
105   while (EOF != (k = fgetc(f))) {
106     if (k == *what) {
107       ++what;
108       while ((*what != '\0') && (*what == fgetc(f))) {
109         ++what;
110       }
111       if (*what == '\0') {
112         fclose(f);
113         return true;
114       } else {
115         what = search_string;
116       }
117     }
118   }
119   fclose(f);
120
121   // Did not find string in the proc file.
122   return false;
123 }
124
125
126 bool OS::ArmCpuHasFeature(CpuFeature feature) {
127   switch (feature) {
128     case VFP3:
129       // All shipping devices currently support this and QNX has no easy way to
130       // determine this at runtime.
131       return true;
132     case ARMv7:
133       return (SYSPAGE_ENTRY(cpuinfo)->flags & ARM_CPU_FLAG_V7) != 0;
134     default:
135       UNREACHABLE();
136   }
137
138   return false;
139 }
140
141
142 // Simple helper function to detect whether the C code is compiled with
143 // option -mfloat-abi=hard. The register d0 is loaded with 1.0 and the register
144 // pair r0, r1 is loaded with 0.0. If -mfloat-abi=hard is pased to GCC then
145 // calling this will return 1.0 and otherwise 0.0.
146 static void ArmUsingHardFloatHelper() {
147   asm("mov r0, #0");
148 #if defined(__VFP_FP__) && !defined(__SOFTFP__)
149   // Load 0x3ff00000 into r1 using instructions available in both ARM
150   // and Thumb mode.
151   asm("mov r1, #3");
152   asm("mov r2, #255");
153   asm("lsl r1, r1, #8");
154   asm("orr r1, r1, r2");
155   asm("lsl r1, r1, #20");
156   // For vmov d0, r0, r1 use ARM mode.
157 #ifdef __thumb__
158   asm volatile(
159     "@   Enter ARM Mode  \n\t"
160     "    adr r3, 1f      \n\t"
161     "    bx  r3          \n\t"
162     "    .ALIGN 4        \n\t"
163     "    .ARM            \n"
164     "1:  vmov d0, r0, r1 \n\t"
165     "@   Enter THUMB Mode\n\t"
166     "    adr r3, 2f+1    \n\t"
167     "    bx  r3          \n\t"
168     "    .THUMB          \n"
169     "2:                  \n\t");
170 #else
171   asm("vmov d0, r0, r1");
172 #endif  // __thumb__
173 #endif  // defined(__VFP_FP__) && !defined(__SOFTFP__)
174   asm("mov r1, #0");
175 }
176
177
178 bool OS::ArmUsingHardFloat() {
179   // Cast helper function from returning void to returning double.
180   typedef double (*F)();
181   F f = FUNCTION_CAST<F>(FUNCTION_ADDR(ArmUsingHardFloatHelper));
182   return f() == 1.0;
183 }
184 #endif  // def __arm__
185
186
187 int OS::ActivationFrameAlignment() {
188 #ifdef V8_TARGET_ARCH_ARM
189   // On EABI ARM targets this is required for fp correctness in the
190   // runtime system.
191   return 8;
192 #endif
193   // With gcc 4.4 the tree vectorization optimizer can generate code
194   // that requires 16 byte alignment such as movdqa on x86.
195   return 16;
196 }
197
198
199 void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
200 #if defined(V8_TARGET_ARCH_ARM) && defined(__arm__)
201   // Only use on ARM hardware.
202   MemoryBarrier();
203 #else
204   __asm__ __volatile__("" : : : "memory");
205   // An x86 store acts as a release barrier.
206 #endif
207   *ptr = value;
208 }
209
210
211 const char* OS::LocalTimezone(double time) {
212   if (isnan(time)) return "";
213   time_t tv = static_cast<time_t>(floor(time/msPerSecond));
214   struct tm* t = localtime(&tv);
215   if (NULL == t) return "";
216   return t->tm_zone;
217 }
218
219
220 double OS::LocalTimeOffset() {
221   time_t tv = time(NULL);
222   struct tm* t = localtime(&tv);
223   // tm_gmtoff includes any daylight savings offset, so subtract it.
224   return static_cast<double>(t->tm_gmtoff * msPerSecond -
225                              (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
226 }
227
228
229 // We keep the lowest and highest addresses mapped as a quick way of
230 // determining that pointers are outside the heap (used mostly in assertions
231 // and verification).  The estimate is conservative, ie, not all addresses in
232 // 'allocated' space are actually allocated to our heap.  The range is
233 // [lowest, highest), inclusive on the low and and exclusive on the high end.
234 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
235 static void* highest_ever_allocated = reinterpret_cast<void*>(0);
236
237
238 static void UpdateAllocatedSpaceLimits(void* address, int size) {
239   ASSERT(limit_mutex != NULL);
240   ScopedLock lock(limit_mutex);
241
242   lowest_ever_allocated = Min(lowest_ever_allocated, address);
243   highest_ever_allocated =
244       Max(highest_ever_allocated,
245           reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
246 }
247
248
249 bool OS::IsOutsideAllocatedSpace(void* address) {
250   return address < lowest_ever_allocated || address >= highest_ever_allocated;
251 }
252
253
254 size_t OS::AllocateAlignment() {
255   return sysconf(_SC_PAGESIZE);
256 }
257
258
259 void* OS::Allocate(const size_t requested,
260                    size_t* allocated,
261                    bool is_executable) {
262   const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE));
263   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
264   void* addr = GetRandomMmapAddr();
265   void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
266   if (mbase == MAP_FAILED) {
267     LOG(i::Isolate::Current(),
268         StringEvent("OS::Allocate", "mmap failed"));
269     return NULL;
270   }
271   *allocated = msize;
272   UpdateAllocatedSpaceLimits(mbase, msize);
273   return mbase;
274 }
275
276
277 void OS::Free(void* address, const size_t size) {
278   // TODO(1240712): munmap has a return value which is ignored here.
279   int result = munmap(address, size);
280   USE(result);
281   ASSERT(result == 0);
282 }
283
284
285 void OS::Sleep(int milliseconds) {
286   unsigned int ms = static_cast<unsigned int>(milliseconds);
287   usleep(1000 * ms);
288 }
289
290
291 void OS::Abort() {
292   // Redirect to std abort to signal abnormal program termination.
293   abort();
294 }
295
296
297 void OS::DebugBreak() {
298 // TODO(lrn): Introduce processor define for runtime system (!= V8_ARCH_x,
299 //  which is the architecture of generated code).
300 #if (defined(__arm__) || defined(__thumb__))
301 # if defined(CAN_USE_ARMV5_INSTRUCTIONS)
302   asm("bkpt 0");
303 # endif
304 #else
305   asm("int $3");
306 #endif
307 }
308
309
310 class PosixMemoryMappedFile : public OS::MemoryMappedFile {
311  public:
312   PosixMemoryMappedFile(FILE* file, void* memory, int size)
313     : file_(file), memory_(memory), size_(size) { }
314   virtual ~PosixMemoryMappedFile();
315   virtual void* memory() { return memory_; }
316   virtual int size() { return size_; }
317  private:
318   FILE* file_;
319   void* memory_;
320   int size_;
321 };
322
323
324 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
325   FILE* file = fopen(name, "r+");
326   if (file == NULL) return NULL;
327
328   fseek(file, 0, SEEK_END);
329   int size = ftell(file);
330
331   void* memory =
332       mmap(OS::GetRandomMmapAddr(),
333            size,
334            PROT_READ | PROT_WRITE,
335            MAP_SHARED,
336            fileno(file),
337            0);
338   return new PosixMemoryMappedFile(file, memory, size);
339 }
340
341
342 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
343     void* initial) {
344   FILE* file = fopen(name, "w+");
345   if (file == NULL) return NULL;
346   int result = fwrite(initial, size, 1, file);
347   if (result < 1) {
348     fclose(file);
349     return NULL;
350   }
351   void* memory =
352       mmap(OS::GetRandomMmapAddr(),
353            size,
354            PROT_READ | PROT_WRITE,
355            MAP_SHARED,
356            fileno(file),
357            0);
358   return new PosixMemoryMappedFile(file, memory, size);
359 }
360
361
362 PosixMemoryMappedFile::~PosixMemoryMappedFile() {
363   if (memory_) munmap(memory_, size_);
364   fclose(file_);
365 }
366
367
368 void OS::LogSharedLibraryAddresses() {
369   procfs_mapinfo *mapinfos = NULL, *mapinfo;
370   int proc_fd, num, i;
371
372   struct {
373     procfs_debuginfo info;
374     char buff[PATH_MAX];
375   } map;
376
377   char buf[PATH_MAX + 1];
378   sprintf(buf, "/proc/%d/as", getpid());
379
380   if ((proc_fd = open(buf, O_RDONLY)) == -1) {
381     close(proc_fd);
382     return;
383   }
384
385   /* Get the number of map entrys.  */
386   if (devctl(proc_fd, DCMD_PROC_MAPINFO, NULL, 0, &num) != EOK) {
387     close(proc_fd);
388     return;
389   }
390
391   mapinfos =(procfs_mapinfo *)malloc(num * sizeof(procfs_mapinfo));
392   if (mapinfos == NULL) {
393     close(proc_fd);
394     return;
395   }
396
397   /* Fill the map entrys.  */
398   if (devctl(proc_fd, DCMD_PROC_PAGEDATA, mapinfos, num * sizeof(procfs_mapinfo), &num) != EOK) {
399     free(mapinfos);
400     close(proc_fd);
401     return;
402   }
403
404   i::Isolate* isolate = ISOLATE;
405
406   for (i = 0; i < num; i++) {
407     mapinfo = mapinfos + i;
408     if (mapinfo->flags & MAP_ELF) {
409       map.info.vaddr = mapinfo->vaddr;
410       if (devctl(proc_fd, DCMD_PROC_MAPDEBUG, &map, sizeof(map), 0) != EOK)
411             continue;
412
413           LOG(isolate, SharedLibraryEvent(map.info.path, mapinfo->vaddr, mapinfo->vaddr + mapinfo->size));
414         }
415   }
416   free(mapinfos);
417   close(proc_fd);
418 }
419
420
421 static const char kGCFakeMmap[] = "/tmp/__v8_gc__";
422
423
424 void OS::SignalCodeMovingGC() {
425   // Support for ll_prof.py.
426   //
427   // The QNX profiler built into the kernel logs all mmap's with
428   // PROT_EXEC so that analysis tools can properly attribute ticks. We
429   // do a mmap with a name known by ll_prof.py and immediately munmap
430   // it. This injects a GC marker into the stream of events generated
431   // by the kernel and allows us to synchronize V8 code log and the
432   // kernel log.
433   int size = sysconf(_SC_PAGESIZE);
434   FILE* f = fopen(kGCFakeMmap, "w+");
435   void* addr = mmap(OS::GetRandomMmapAddr(),
436                     size,
437                     PROT_READ | PROT_EXEC,
438                     MAP_PRIVATE,
439                     fileno(f),
440                     0);
441   ASSERT(addr != MAP_FAILED);
442   munmap(addr, size);
443   fclose(f);
444 }
445
446
447 int OS::StackWalk(Vector<OS::StackFrame> frames) {
448   int frames_size = frames.length();
449   bt_addr_t addresses[frames_size];
450   bt_accessor_t acc;
451   bt_memmap_t memmap;
452   bt_init_accessor(&acc, BT_SELF);
453   bt_load_memmap(&acc, &memmap);
454   int frames_count = bt_get_backtrace(&acc, addresses, frames_size);
455   bt_addr_t temp_addr[1];
456   for (int i = 0; i < frames_count; i++) {
457     frames[i].address = reinterpret_cast<void*>(addresses[i]);
458     temp_addr[0] = addresses[i];
459     // Format a text representation of the frame based on the information
460     // available.
461     bt_sprnf_addrs(&memmap, temp_addr, 1, "%a", frames[i].text, kStackWalkMaxTextLen, 0);
462     // Make sure line termination is in place.
463     frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
464   }
465   bt_unload_memmap(&memmap);
466   bt_release_accessor(&acc);
467   return 0;
468 }
469
470
471 // Constants used for mmap.
472 static const int kMmapFd = -1;
473 static const int kMmapFdOffset = 0;
474
475 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
476
477 VirtualMemory::VirtualMemory(size_t size) {
478   address_ = ReserveRegion(size);
479   size_ = size;
480 }
481
482
483 VirtualMemory::VirtualMemory(size_t size, size_t alignment)
484     : address_(NULL), size_(0) {
485   ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
486   size_t request_size = RoundUp(size + alignment,
487                                 static_cast<intptr_t>(OS::AllocateAlignment()));
488   void* reservation = mmap(OS::GetRandomMmapAddr(),
489                            request_size,
490                            PROT_NONE,
491                            MAP_PRIVATE | MAP_ANONYMOUS,
492                            kMmapFd,
493                            kMmapFdOffset);
494   if (reservation == MAP_FAILED) return;
495
496   Address base = static_cast<Address>(reservation);
497   Address aligned_base = RoundUp(base, alignment);
498   ASSERT_LE(base, aligned_base);
499
500   // Unmap extra memory reserved before and after the desired block.
501   if (aligned_base != base) {
502     size_t prefix_size = static_cast<size_t>(aligned_base - base);
503     OS::Free(base, prefix_size);
504     request_size -= prefix_size;
505   }
506
507   size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
508   ASSERT_LE(aligned_size, request_size);
509
510   if (aligned_size != request_size) {
511     size_t suffix_size = request_size - aligned_size;
512     OS::Free(aligned_base + aligned_size, suffix_size);
513     request_size -= suffix_size;
514   }
515
516   ASSERT(aligned_size == request_size);
517
518   address_ = static_cast<void*>(aligned_base);
519   size_ = aligned_size;
520 }
521
522
523 VirtualMemory::~VirtualMemory() {
524   if (IsReserved()) {
525     bool result = ReleaseRegion(address(), size());
526     ASSERT(result);
527     USE(result);
528   }
529 }
530
531
532 bool VirtualMemory::IsReserved() {
533   return address_ != NULL;
534 }
535
536
537 void VirtualMemory::Reset() {
538   address_ = NULL;
539   size_ = 0;
540 }
541
542
543 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
544   return CommitRegion(address, size, is_executable);
545 }
546
547
548 bool VirtualMemory::Uncommit(void* address, size_t size) {
549   return UncommitRegion(address, size);
550 }
551
552
553 bool VirtualMemory::Guard(void* address) {
554   OS::Guard(address, OS::CommitPageSize());
555   return true;
556 }
557
558
559 void* VirtualMemory::ReserveRegion(size_t size) {
560   void* result = mmap(OS::GetRandomMmapAddr(),
561                       size,
562                       PROT_NONE,
563                       MAP_PRIVATE | MAP_ANONYMOUS,
564                       kMmapFd,
565                       kMmapFdOffset);
566
567   if (result == MAP_FAILED) return NULL;
568
569   return result;
570 }
571
572
573 bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
574   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
575   if (MAP_FAILED == mmap(base,
576                          size,
577                          prot,
578                          MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
579                          kMmapFd,
580                          kMmapFdOffset)) {
581     return false;
582   }
583
584   UpdateAllocatedSpaceLimits(base, size);
585   return true;
586 }
587
588
589 bool VirtualMemory::UncommitRegion(void* base, size_t size) {
590   return mmap(base,
591               size,
592               PROT_NONE,
593               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
594               kMmapFd,
595               kMmapFdOffset) != MAP_FAILED;
596 }
597
598
599 bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
600   return munmap(base, size) == 0;
601 }
602
603
604 class Thread::PlatformData : public Malloced {
605  public:
606   PlatformData() : thread_(kNoThread) {}
607
608   pthread_t thread_;  // Thread handle for pthread.
609 };
610
611 Thread::Thread(const Options& options)
612     : data_(new PlatformData()),
613       stack_size_(options.stack_size()) {
614   set_name(options.name());
615 }
616
617
618 Thread::~Thread() {
619   delete data_;
620 }
621
622
623 static void* ThreadEntry(void* arg) {
624   Thread* thread = reinterpret_cast<Thread*>(arg);
625   // This is also initialized by the first argument to pthread_create() but we
626   // don't know which thread will run first (the original thread or the new
627   // one) so we initialize it here too.
628 #ifdef PR_SET_NAME
629   prctl(PR_SET_NAME,
630         reinterpret_cast<unsigned long>(thread->name()),  // NOLINT
631         0, 0, 0);
632 #endif
633   thread->data()->thread_ = pthread_self();
634   ASSERT(thread->data()->thread_ != kNoThread);
635   thread->Run();
636   return NULL;
637 }
638
639
640 void Thread::set_name(const char* name) {
641   strncpy(name_, name, sizeof(name_));
642   name_[sizeof(name_) - 1] = '\0';
643 }
644
645
646 void Thread::Start() {
647   pthread_attr_t* attr_ptr = NULL;
648   pthread_attr_t attr;
649   if (stack_size_ > 0) {
650     pthread_attr_init(&attr);
651     pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
652     attr_ptr = &attr;
653   }
654   int result = pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
655   CHECK_EQ(0, result);
656   ASSERT(data_->thread_ != kNoThread);
657 }
658
659
660 void Thread::Join() {
661   pthread_join(data_->thread_, NULL);
662 }
663
664
665 Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
666   pthread_key_t key;
667   int result = pthread_key_create(&key, NULL);
668   USE(result);
669   ASSERT(result == 0);
670   return static_cast<LocalStorageKey>(key);
671 }
672
673
674 void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
675   pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
676   int result = pthread_key_delete(pthread_key);
677   USE(result);
678   ASSERT(result == 0);
679 }
680
681
682 void* Thread::GetThreadLocal(LocalStorageKey key) {
683   pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
684   return pthread_getspecific(pthread_key);
685 }
686
687
688 void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
689   pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
690   pthread_setspecific(pthread_key, value);
691 }
692
693
694 void Thread::YieldCPU() {
695   sched_yield();
696 }
697
698
699 class QNXMutex : public Mutex {
700  public:
701   QNXMutex() {
702     pthread_mutexattr_t attrs;
703     int result = pthread_mutexattr_init(&attrs);
704     ASSERT(result == 0);
705     result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
706     ASSERT(result == 0);
707     result = pthread_mutex_init(&mutex_, &attrs);
708     ASSERT(result == 0);
709     USE(result);
710   }
711
712   virtual ~QNXMutex() { pthread_mutex_destroy(&mutex_); }
713
714   virtual int Lock() {
715     int result = pthread_mutex_lock(&mutex_);
716     return result;
717   }
718
719   virtual int Unlock() {
720     int result = pthread_mutex_unlock(&mutex_);
721     return result;
722   }
723
724   virtual bool TryLock() {
725     int result = pthread_mutex_trylock(&mutex_);
726     // Return false if the lock is busy and locking failed.
727     if (result == EBUSY) {
728       return false;
729     }
730     ASSERT(result == 0);  // Verify no other errors.
731     return true;
732   }
733
734  private:
735   pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
736 };
737
738
739 Mutex* OS::CreateMutex() {
740   return new QNXMutex();
741 }
742
743
744 class QNXSemaphore : public Semaphore {
745  public:
746   explicit QNXSemaphore(int count) {  sem_init(&sem_, 0, count); }
747   virtual ~QNXSemaphore() { sem_destroy(&sem_); }
748
749   virtual void Wait();
750   virtual bool Wait(int timeout);
751   virtual void Signal() { sem_post(&sem_); }
752  private:
753   sem_t sem_;
754 };
755
756
757 void QNXSemaphore::Wait() {
758   while (true) {
759     int result = sem_wait(&sem_);
760     if (result == 0) return;  // Successfully got semaphore.
761     CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
762   }
763 }
764
765
766 #ifndef TIMEVAL_TO_TIMESPEC
767 #define TIMEVAL_TO_TIMESPEC(tv, ts) do {                            \
768     (ts)->tv_sec = (tv)->tv_sec;                                    \
769     (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
770 } while (false)
771 #endif
772
773
774 bool QNXSemaphore::Wait(int timeout) {
775   const long kOneSecondMicros = 1000000;  // NOLINT
776
777   // Split timeout into second and nanosecond parts.
778   struct timeval delta;
779   delta.tv_usec = timeout % kOneSecondMicros;
780   delta.tv_sec = timeout / kOneSecondMicros;
781
782   struct timeval current_time;
783   // Get the current time.
784   if (gettimeofday(&current_time, NULL) == -1) {
785     return false;
786   }
787
788   // Calculate time for end of timeout.
789   struct timeval end_time;
790   timeradd(&current_time, &delta, &end_time);
791
792   struct timespec ts;
793   TIMEVAL_TO_TIMESPEC(&end_time, &ts);
794   // Wait for semaphore signalled or timeout.
795   while (true) {
796     int result = sem_timedwait(&sem_, &ts);
797     if (result == 0) return true;  // Successfully got semaphore.
798     if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
799     CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
800   }
801 }
802
803
804 Semaphore* OS::CreateSemaphore(int count) {
805   return new QNXSemaphore(count);
806 }
807
808
809 static int GetThreadID() {
810   pthread_t thread_id = pthread_self();
811   return thread_id;
812 }
813
814
815 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
816   USE(info);
817   if (signal != SIGPROF) return;
818   Isolate* isolate = Isolate::UncheckedCurrent();
819   if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
820     // We require a fully initialized and entered isolate.
821     return;
822   }
823   if (v8::Locker::IsActive() &&
824       !isolate->thread_manager()->IsLockedByCurrentThread()) {
825     return;
826   }
827
828   Sampler* sampler = isolate->logger()->sampler();
829   if (sampler == NULL || !sampler->IsActive()) return;
830
831   TickSample sample_obj;
832   TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
833   if (sample == NULL) sample = &sample_obj;
834
835   // Extracting the sample from the context is extremely machine dependent.
836   ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
837   mcontext_t& mcontext = ucontext->uc_mcontext;
838   sample->state = isolate->current_vm_state();
839 #if V8_HOST_ARCH_IA32
840   sample->pc = reinterpret_cast<Address>(mcontext.cpu.eip);
841   sample->sp = reinterpret_cast<Address>(mcontext.cpu.esp);
842   sample->fp = reinterpret_cast<Address>(mcontext.cpu.ebp);
843 #elif V8_HOST_ARCH_X64
844   sample->pc = reinterpret_cast<Address>(mcontext.cpu.rip);
845   sample->sp = reinterpret_cast<Address>(mcontext.cpu.rsp);
846   sample->fp = reinterpret_cast<Address>(mcontext.cpu.rbp);
847 #elif V8_HOST_ARCH_ARM
848   sample->pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]);
849   sample->sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]);
850   sample->fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]);
851 #endif
852   sampler->SampleStack(sample);
853   sampler->Tick(sample);
854 }
855
856
857 class Sampler::PlatformData : public Malloced {
858  public:
859   PlatformData() : vm_tid_(GetThreadID()) {}
860
861   int vm_tid() const { return vm_tid_; }
862
863  private:
864   const int vm_tid_;
865 };
866
867
868 class SignalSender : public Thread {
869  public:
870   enum SleepInterval {
871     HALF_INTERVAL,
872     FULL_INTERVAL
873   };
874
875   static const int kSignalSenderStackSize = 32 * KB;
876
877   explicit SignalSender(int interval)
878       : Thread("SignalSender"),
879         vm_tgid_(getpid()),
880         interval_(interval) {}
881
882   static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
883   static void TearDown() { delete mutex_; }
884
885   static void InstallSignalHandler() {
886     struct sigaction sa;
887     sa.sa_sigaction = ProfilerSignalHandler;
888     sigemptyset(&sa.sa_mask);
889     sa.sa_flags = SA_SIGINFO;
890     signal_handler_installed_ =
891         (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
892   }
893
894   static void RestoreSignalHandler() {
895     if (signal_handler_installed_) {
896       sigaction(SIGPROF, &old_signal_handler_, 0);
897       signal_handler_installed_ = false;
898     }
899   }
900
901   static void AddActiveSampler(Sampler* sampler) {
902     ScopedLock lock(mutex_);
903     SamplerRegistry::AddActiveSampler(sampler);
904     if (instance_ == NULL) {
905       // Start a thread that will send SIGPROF signal to VM threads,
906       // when CPU profiling will be enabled.
907       instance_ = new SignalSender(sampler->interval());
908       instance_->Start();
909     } else {
910       ASSERT(instance_->interval_ == sampler->interval());
911     }
912   }
913
914   static void RemoveActiveSampler(Sampler* sampler) {
915     ScopedLock lock(mutex_);
916     SamplerRegistry::RemoveActiveSampler(sampler);
917     if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
918       RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
919       delete instance_;
920       instance_ = NULL;
921       RestoreSignalHandler();
922     }
923   }
924
925   // Implement Thread::Run().
926   virtual void Run() {
927     SamplerRegistry::State state;
928     while ((state = SamplerRegistry::GetState()) !=
929            SamplerRegistry::HAS_NO_SAMPLERS) {
930       bool cpu_profiling_enabled =
931           (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
932       bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
933       if (cpu_profiling_enabled && !signal_handler_installed_) {
934         InstallSignalHandler();
935       } else if (!cpu_profiling_enabled && signal_handler_installed_) {
936         RestoreSignalHandler();
937       }
938       // When CPU profiling is enabled both JavaScript and C++ code is
939       // profiled. We must not suspend.
940       if (!cpu_profiling_enabled) {
941         if (rate_limiter_.SuspendIfNecessary()) continue;
942       }
943       if (cpu_profiling_enabled && runtime_profiler_enabled) {
944         if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
945           return;
946         }
947         Sleep(HALF_INTERVAL);
948         if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
949           return;
950         }
951         Sleep(HALF_INTERVAL);
952       } else {
953         if (cpu_profiling_enabled) {
954           if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
955                                                       this)) {
956             return;
957           }
958         }
959         if (runtime_profiler_enabled) {
960           if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
961                                                       NULL)) {
962             return;
963           }
964         }
965         Sleep(FULL_INTERVAL);
966       }
967     }
968   }
969
970   static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
971     if (!sampler->IsProfiling()) return;
972     SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
973     sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
974   }
975
976   static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
977     if (!sampler->isolate()->IsInitialized()) return;
978     sampler->isolate()->runtime_profiler()->NotifyTick();
979   }
980
981   void SendProfilingSignal(int tid) {
982     if (!signal_handler_installed_) return;
983     pthread_kill(tid, SIGPROF);
984   }
985
986   void Sleep(SleepInterval full_or_half) {
987     // Convert ms to us and subtract 100 us to compensate delays
988     // occuring during signal delivery.
989     useconds_t interval = interval_ * 1000 - 100;
990     if (full_or_half == HALF_INTERVAL) interval /= 2;
991     int result = usleep(interval);
992 #ifdef DEBUG
993     if (result != 0 && errno != EINTR) {
994       fprintf(stderr,
995               "SignalSender usleep error; interval = %u, errno = %d\n",
996               interval,
997               errno);
998       ASSERT(result == 0 || errno == EINTR);
999     }
1000 #endif
1001     USE(result);
1002   }
1003
1004   const int vm_tgid_;
1005   const int interval_;
1006   RuntimeProfilerRateLimiter rate_limiter_;
1007
1008   // Protects the process wide state below.
1009   static Mutex* mutex_;
1010   static SignalSender* instance_;
1011   static bool signal_handler_installed_;
1012   static struct sigaction old_signal_handler_;
1013
1014   DISALLOW_COPY_AND_ASSIGN(SignalSender);
1015 };
1016
1017
1018 Mutex* SignalSender::mutex_ = NULL;
1019 SignalSender* SignalSender::instance_ = NULL;
1020 struct sigaction SignalSender::old_signal_handler_;
1021 bool SignalSender::signal_handler_installed_ = false;
1022
1023
1024 void OS::SetUp() {
1025   // Seed the random number generator. We preserve microsecond resolution.
1026   uint64_t seed = Ticks() ^ (getpid() << 16);
1027   srandom(static_cast<unsigned int>(seed));
1028   limit_mutex = CreateMutex();
1029
1030 #ifdef __arm__
1031   // When running on ARM hardware check that the EABI used by V8 and
1032   // by the C code is the same.
1033   bool hard_float = OS::ArmUsingHardFloat();
1034   if (hard_float) {
1035 #if !USE_EABI_HARDFLOAT
1036     PrintF("ERROR: Binary compiled with -mfloat-abi=hard but without "
1037            "-DUSE_EABI_HARDFLOAT\n");
1038     exit(1);
1039 #endif
1040   } else {
1041 #if USE_EABI_HARDFLOAT
1042     PrintF("ERROR: Binary not compiled with -mfloat-abi=hard but with "
1043            "-DUSE_EABI_HARDFLOAT\n");
1044     exit(1);
1045 #endif
1046   }
1047 #endif
1048   SignalSender::SetUp();
1049 }
1050
1051
1052 void OS::TearDown() {
1053   SignalSender::TearDown();
1054   delete limit_mutex;
1055 }
1056
1057
1058 Sampler::Sampler(Isolate* isolate, int interval)
1059     : isolate_(isolate),
1060       interval_(interval),
1061       profiling_(false),
1062       active_(false),
1063       samples_taken_(0) {
1064   data_ = new PlatformData;
1065 }
1066
1067
1068 Sampler::~Sampler() {
1069   ASSERT(!IsActive());
1070   delete data_;
1071 }
1072
1073
1074 void Sampler::Start() {
1075   ASSERT(!IsActive());
1076   SetActive(true);
1077   SignalSender::AddActiveSampler(this);
1078 }
1079
1080
1081 void Sampler::Stop() {
1082   ASSERT(IsActive());
1083   SignalSender::RemoveActiveSampler(this);
1084   SetActive(false);
1085 }
1086
1087
1088 } }  // namespace v8::internal