Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / v8 / src / platform-posix.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Platform-specific code for POSIX goes here. This is not a platform on its
6 // own, but contains the parts which are the same across the POSIX platforms
7 // Linux, MacOS, FreeBSD, OpenBSD, NetBSD and QNX.
8
9 #include <dlfcn.h>
10 #include <pthread.h>
11 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
12 #include <pthread_np.h>  // for pthread_set_name_np
13 #endif
14 #include <sched.h>  // for sched_yield
15 #include <unistd.h>
16 #include <errno.h>
17 #include <time.h>
18
19 #include <sys/mman.h>
20 #include <sys/resource.h>
21 #include <sys/time.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #if defined(__linux__)
25 #include <sys/prctl.h>  // for prctl
26 #endif
27 #if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
28     defined(__NetBSD__) || defined(__OpenBSD__)
29 #include <sys/sysctl.h>  // for sysctl
30 #endif
31
32 #include <arpa/inet.h>
33 #include <netinet/in.h>
34 #include <netdb.h>
35
36 #undef MAP_TYPE
37
38 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
39 #define LOG_TAG "v8"
40 #include <android/log.h>
41 #endif
42
43 #include "src/v8.h"
44
45 #include "src/isolate-inl.h"
46 #include "src/platform.h"
47
48 #ifdef V8_FAST_TLS_SUPPORTED
49 #include "src/base/atomicops.h"
50 #endif
51
52 namespace v8 {
53 namespace internal {
54
55 // 0 is never a valid thread id.
56 static const pthread_t kNoThread = (pthread_t) 0;
57
58
59 int OS::NumberOfProcessorsOnline() {
60   return static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
61 }
62
63
64 // Maximum size of the virtual memory.  0 means there is no artificial
65 // limit.
66
67 intptr_t OS::MaxVirtualMemory() {
68   struct rlimit limit;
69   int result = getrlimit(RLIMIT_DATA, &limit);
70   if (result != 0) return 0;
71 #if V8_OS_NACL
72   // The NaCl compiler doesn't like resource.h constants.
73   if (static_cast<int>(limit.rlim_cur) == -1) return 0;
74 #else
75   if (limit.rlim_cur == RLIM_INFINITY) return 0;
76 #endif
77   return limit.rlim_cur;
78 }
79
80
81 uint64_t OS::TotalPhysicalMemory() {
82 #if V8_OS_MACOSX
83   int mib[2];
84   mib[0] = CTL_HW;
85   mib[1] = HW_MEMSIZE;
86   int64_t size = 0;
87   size_t len = sizeof(size);
88   if (sysctl(mib, 2, &size, &len, NULL, 0) != 0) {
89     UNREACHABLE();
90     return 0;
91   }
92   return static_cast<uint64_t>(size);
93 #elif V8_OS_FREEBSD
94   int pages, page_size;
95   size_t size = sizeof(pages);
96   sysctlbyname("vm.stats.vm.v_page_count", &pages, &size, NULL, 0);
97   sysctlbyname("vm.stats.vm.v_page_size", &page_size, &size, NULL, 0);
98   if (pages == -1 || page_size == -1) {
99     UNREACHABLE();
100     return 0;
101   }
102   return static_cast<uint64_t>(pages) * page_size;
103 #elif V8_OS_CYGWIN
104   MEMORYSTATUS memory_info;
105   memory_info.dwLength = sizeof(memory_info);
106   if (!GlobalMemoryStatus(&memory_info)) {
107     UNREACHABLE();
108     return 0;
109   }
110   return static_cast<uint64_t>(memory_info.dwTotalPhys);
111 #elif V8_OS_QNX
112   struct stat stat_buf;
113   if (stat("/proc", &stat_buf) != 0) {
114     UNREACHABLE();
115     return 0;
116   }
117   return static_cast<uint64_t>(stat_buf.st_size);
118 #else
119   intptr_t pages = sysconf(_SC_PHYS_PAGES);
120   intptr_t page_size = sysconf(_SC_PAGESIZE);
121   if (pages == -1 || page_size == -1) {
122     UNREACHABLE();
123     return 0;
124   }
125   return static_cast<uint64_t>(pages) * page_size;
126 #endif
127 }
128
129
130 int OS::ActivationFrameAlignment() {
131 #if V8_TARGET_ARCH_ARM
132   // On EABI ARM targets this is required for fp correctness in the
133   // runtime system.
134   return 8;
135 #elif V8_TARGET_ARCH_MIPS
136   return 8;
137 #else
138   // Otherwise we just assume 16 byte alignment, i.e.:
139   // - With gcc 4.4 the tree vectorization optimizer can generate code
140   //   that requires 16 byte alignment such as movdqa on x86.
141   // - Mac OS X and Solaris (64-bit) activation frames must be 16 byte-aligned;
142   //   see "Mac OS X ABI Function Call Guide"
143   return 16;
144 #endif
145 }
146
147
148 intptr_t OS::CommitPageSize() {
149   static intptr_t page_size = getpagesize();
150   return page_size;
151 }
152
153
154 void OS::Free(void* address, const size_t size) {
155   // TODO(1240712): munmap has a return value which is ignored here.
156   int result = munmap(address, size);
157   USE(result);
158   ASSERT(result == 0);
159 }
160
161
162 // Get rid of writable permission on code allocations.
163 void OS::ProtectCode(void* address, const size_t size) {
164 #if V8_OS_CYGWIN
165   DWORD old_protect;
166   VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect);
167 #elif V8_OS_NACL
168   // The Native Client port of V8 uses an interpreter, so
169   // code pages don't need PROT_EXEC.
170   mprotect(address, size, PROT_READ);
171 #else
172   mprotect(address, size, PROT_READ | PROT_EXEC);
173 #endif
174 }
175
176
177 // Create guard pages.
178 void OS::Guard(void* address, const size_t size) {
179 #if V8_OS_CYGWIN
180   DWORD oldprotect;
181   VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect);
182 #else
183   mprotect(address, size, PROT_NONE);
184 #endif
185 }
186
187
188 void* OS::GetRandomMmapAddr() {
189 #if V8_OS_NACL
190   // TODO(bradchen): restore randomization once Native Client gets
191   // smarter about using mmap address hints.
192   // See http://code.google.com/p/nativeclient/issues/3341
193   return NULL;
194 #endif
195 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
196     defined(THREAD_SANITIZER)
197   // Dynamic tools do not support custom mmap addresses.
198   return NULL;
199 #endif
200   Isolate* isolate = Isolate::UncheckedCurrent();
201   // Note that the current isolate isn't set up in a call path via
202   // CpuFeatures::Probe. We don't care about randomization in this case because
203   // the code page is immediately freed.
204   if (isolate != NULL) {
205     uintptr_t raw_addr;
206     isolate->random_number_generator()->NextBytes(&raw_addr, sizeof(raw_addr));
207 #if V8_TARGET_ARCH_X64
208     // Currently available CPUs have 48 bits of virtual addressing.  Truncate
209     // the hint address to 46 bits to give the kernel a fighting chance of
210     // fulfilling our placement request.
211     raw_addr &= V8_UINT64_C(0x3ffffffff000);
212 #else
213     raw_addr &= 0x3ffff000;
214
215 # ifdef __sun
216     // For our Solaris/illumos mmap hint, we pick a random address in the bottom
217     // half of the top half of the address space (that is, the third quarter).
218     // Because we do not MAP_FIXED, this will be treated only as a hint -- the
219     // system will not fail to mmap() because something else happens to already
220     // be mapped at our random address. We deliberately set the hint high enough
221     // to get well above the system's break (that is, the heap); Solaris and
222     // illumos will try the hint and if that fails allocate as if there were
223     // no hint at all. The high hint prevents the break from getting hemmed in
224     // at low values, ceding half of the address space to the system heap.
225     raw_addr += 0x80000000;
226 # else
227     // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
228     // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos
229     // 10.6 and 10.7.
230     raw_addr += 0x20000000;
231 # endif
232 #endif
233     return reinterpret_cast<void*>(raw_addr);
234   }
235   return NULL;
236 }
237
238
239 size_t OS::AllocateAlignment() {
240   return static_cast<size_t>(sysconf(_SC_PAGESIZE));
241 }
242
243
244 void OS::Sleep(int milliseconds) {
245   useconds_t ms = static_cast<useconds_t>(milliseconds);
246   usleep(1000 * ms);
247 }
248
249
250 void OS::Abort() {
251   if (FLAG_hard_abort) {
252     V8_IMMEDIATE_CRASH();
253   }
254   // Redirect to std abort to signal abnormal program termination.
255   abort();
256 }
257
258
259 void OS::DebugBreak() {
260 #if V8_HOST_ARCH_ARM
261   asm("bkpt 0");
262 #elif V8_HOST_ARCH_ARM64
263   asm("brk 0");
264 #elif V8_HOST_ARCH_MIPS
265   asm("break");
266 #elif V8_HOST_ARCH_IA32
267 #if defined(__native_client__)
268   asm("hlt");
269 #else
270   asm("int $3");
271 #endif  // __native_client__
272 #elif V8_HOST_ARCH_X64
273   asm("int $3");
274 #else
275 #error Unsupported host architecture.
276 #endif
277 }
278
279
280 // ----------------------------------------------------------------------------
281 // Math functions
282
283 double OS::nan_value() {
284   // NAN from math.h is defined in C99 and not in POSIX.
285   return NAN;
286 }
287
288
289 int OS::GetCurrentProcessId() {
290   return static_cast<int>(getpid());
291 }
292
293
294 // ----------------------------------------------------------------------------
295 // POSIX date/time support.
296 //
297
298 int OS::GetUserTime(uint32_t* secs,  uint32_t* usecs) {
299   struct rusage usage;
300
301   if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
302   *secs = usage.ru_utime.tv_sec;
303   *usecs = usage.ru_utime.tv_usec;
304   return 0;
305 }
306
307
308 double OS::TimeCurrentMillis() {
309   return Time::Now().ToJsTime();
310 }
311
312
313 class TimezoneCache {};
314
315
316 TimezoneCache* OS::CreateTimezoneCache() {
317   return NULL;
318 }
319
320
321 void OS::DisposeTimezoneCache(TimezoneCache* cache) {
322   ASSERT(cache == NULL);
323 }
324
325
326 void OS::ClearTimezoneCache(TimezoneCache* cache) {
327   ASSERT(cache == NULL);
328 }
329
330
331 double OS::DaylightSavingsOffset(double time, TimezoneCache*) {
332   if (std::isnan(time)) return nan_value();
333   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
334   struct tm* t = localtime(&tv);
335   if (NULL == t) return nan_value();
336   return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
337 }
338
339
340 int OS::GetLastError() {
341   return errno;
342 }
343
344
345 // ----------------------------------------------------------------------------
346 // POSIX stdio support.
347 //
348
349 FILE* OS::FOpen(const char* path, const char* mode) {
350   FILE* file = fopen(path, mode);
351   if (file == NULL) return NULL;
352   struct stat file_stat;
353   if (fstat(fileno(file), &file_stat) != 0) return NULL;
354   bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
355   if (is_regular_file) return file;
356   fclose(file);
357   return NULL;
358 }
359
360
361 bool OS::Remove(const char* path) {
362   return (remove(path) == 0);
363 }
364
365
366 FILE* OS::OpenTemporaryFile() {
367   return tmpfile();
368 }
369
370
371 const char* const OS::LogFileOpenMode = "w";
372
373
374 void OS::Print(const char* format, ...) {
375   va_list args;
376   va_start(args, format);
377   VPrint(format, args);
378   va_end(args);
379 }
380
381
382 void OS::VPrint(const char* format, va_list args) {
383 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
384   __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
385 #else
386   vprintf(format, args);
387 #endif
388 }
389
390
391 void OS::FPrint(FILE* out, const char* format, ...) {
392   va_list args;
393   va_start(args, format);
394   VFPrint(out, format, args);
395   va_end(args);
396 }
397
398
399 void OS::VFPrint(FILE* out, const char* format, va_list args) {
400 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
401   __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
402 #else
403   vfprintf(out, format, args);
404 #endif
405 }
406
407
408 void OS::PrintError(const char* format, ...) {
409   va_list args;
410   va_start(args, format);
411   VPrintError(format, args);
412   va_end(args);
413 }
414
415
416 void OS::VPrintError(const char* format, va_list args) {
417 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
418   __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
419 #else
420   vfprintf(stderr, format, args);
421 #endif
422 }
423
424
425 int OS::SNPrintF(char* str, int length, const char* format, ...) {
426   va_list args;
427   va_start(args, format);
428   int result = VSNPrintF(str, length, format, args);
429   va_end(args);
430   return result;
431 }
432
433
434 int OS::VSNPrintF(char* str,
435                   int length,
436                   const char* format,
437                   va_list args) {
438   int n = vsnprintf(str, length, format, args);
439   if (n < 0 || n >= length) {
440     // If the length is zero, the assignment fails.
441     if (length > 0)
442       str[length - 1] = '\0';
443     return -1;
444   } else {
445     return n;
446   }
447 }
448
449
450 // ----------------------------------------------------------------------------
451 // POSIX string support.
452 //
453
454 char* OS::StrChr(char* str, int c) {
455   return strchr(str, c);
456 }
457
458
459 void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
460   strncpy(dest, src, n);
461 }
462
463
464 // ----------------------------------------------------------------------------
465 // POSIX thread support.
466 //
467
468 class Thread::PlatformData : public Malloced {
469  public:
470   PlatformData() : thread_(kNoThread) {}
471   pthread_t thread_;  // Thread handle for pthread.
472   // Synchronizes thread creation
473   Mutex thread_creation_mutex_;
474 };
475
476 Thread::Thread(const Options& options)
477     : data_(new PlatformData),
478       stack_size_(options.stack_size()),
479       start_semaphore_(NULL) {
480   if (stack_size_ > 0 && stack_size_ < PTHREAD_STACK_MIN) {
481     stack_size_ = PTHREAD_STACK_MIN;
482   }
483   set_name(options.name());
484 }
485
486
487 Thread::~Thread() {
488   delete data_;
489 }
490
491
492 static void SetThreadName(const char* name) {
493 #if V8_OS_DRAGONFLYBSD || V8_OS_FREEBSD || V8_OS_OPENBSD
494   pthread_set_name_np(pthread_self(), name);
495 #elif V8_OS_NETBSD
496   STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP);
497   pthread_setname_np(pthread_self(), "%s", name);
498 #elif V8_OS_MACOSX
499   // pthread_setname_np is only available in 10.6 or later, so test
500   // for it at runtime.
501   int (*dynamic_pthread_setname_np)(const char*);
502   *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
503     dlsym(RTLD_DEFAULT, "pthread_setname_np");
504   if (dynamic_pthread_setname_np == NULL)
505     return;
506
507   // Mac OS X does not expose the length limit of the name, so hardcode it.
508   static const int kMaxNameLength = 63;
509   STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
510   dynamic_pthread_setname_np(name);
511 #elif defined(PR_SET_NAME)
512   prctl(PR_SET_NAME,
513         reinterpret_cast<unsigned long>(name),  // NOLINT
514         0, 0, 0);
515 #endif
516 }
517
518
519 static void* ThreadEntry(void* arg) {
520   Thread* thread = reinterpret_cast<Thread*>(arg);
521   // We take the lock here to make sure that pthread_create finished first since
522   // we don't know which thread will run first (the original thread or the new
523   // one).
524   { LockGuard<Mutex> lock_guard(&thread->data()->thread_creation_mutex_); }
525   SetThreadName(thread->name());
526   ASSERT(thread->data()->thread_ != kNoThread);
527   thread->NotifyStartedAndRun();
528   return NULL;
529 }
530
531
532 void Thread::set_name(const char* name) {
533   strncpy(name_, name, sizeof(name_));
534   name_[sizeof(name_) - 1] = '\0';
535 }
536
537
538 void Thread::Start() {
539   int result;
540   pthread_attr_t attr;
541   memset(&attr, 0, sizeof(attr));
542   result = pthread_attr_init(&attr);
543   ASSERT_EQ(0, result);
544   // Native client uses default stack size.
545 #if !V8_OS_NACL
546   if (stack_size_ > 0) {
547     result = pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
548     ASSERT_EQ(0, result);
549   }
550 #endif
551   {
552     LockGuard<Mutex> lock_guard(&data_->thread_creation_mutex_);
553     result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
554   }
555   ASSERT_EQ(0, result);
556   result = pthread_attr_destroy(&attr);
557   ASSERT_EQ(0, result);
558   ASSERT(data_->thread_ != kNoThread);
559   USE(result);
560 }
561
562
563 void Thread::Join() {
564   pthread_join(data_->thread_, NULL);
565 }
566
567
568 void Thread::YieldCPU() {
569   int result = sched_yield();
570   ASSERT_EQ(0, result);
571   USE(result);
572 }
573
574
575 static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) {
576 #if V8_OS_CYGWIN
577   // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
578   // because pthread_key_t is a pointer type on Cygwin. This will probably not
579   // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
580   STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
581   intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
582   return static_cast<Thread::LocalStorageKey>(ptr_key);
583 #else
584   return static_cast<Thread::LocalStorageKey>(pthread_key);
585 #endif
586 }
587
588
589 static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) {
590 #if V8_OS_CYGWIN
591   STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
592   intptr_t ptr_key = static_cast<intptr_t>(local_key);
593   return reinterpret_cast<pthread_key_t>(ptr_key);
594 #else
595   return static_cast<pthread_key_t>(local_key);
596 #endif
597 }
598
599
600 #ifdef V8_FAST_TLS_SUPPORTED
601
602 static base::Atomic32 tls_base_offset_initialized = 0;
603 intptr_t kMacTlsBaseOffset = 0;
604
605 // It's safe to do the initialization more that once, but it has to be
606 // done at least once.
607 static void InitializeTlsBaseOffset() {
608   const size_t kBufferSize = 128;
609   char buffer[kBufferSize];
610   size_t buffer_size = kBufferSize;
611   int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
612   if (sysctl(ctl_name, 2, buffer, &buffer_size, NULL, 0) != 0) {
613     V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
614   }
615   // The buffer now contains a string of the form XX.YY.ZZ, where
616   // XX is the major kernel version component.
617   // Make sure the buffer is 0-terminated.
618   buffer[kBufferSize - 1] = '\0';
619   char* period_pos = strchr(buffer, '.');
620   *period_pos = '\0';
621   int kernel_version_major =
622       static_cast<int>(strtol(buffer, NULL, 10));  // NOLINT
623   // The constants below are taken from pthreads.s from the XNU kernel
624   // sources archive at www.opensource.apple.com.
625   if (kernel_version_major < 11) {
626     // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the
627     // same offsets.
628 #if V8_HOST_ARCH_IA32
629     kMacTlsBaseOffset = 0x48;
630 #else
631     kMacTlsBaseOffset = 0x60;
632 #endif
633   } else {
634     // 11.x.x (Lion) changed the offset.
635     kMacTlsBaseOffset = 0;
636   }
637
638   base::Release_Store(&tls_base_offset_initialized, 1);
639 }
640
641
642 static void CheckFastTls(Thread::LocalStorageKey key) {
643   void* expected = reinterpret_cast<void*>(0x1234CAFE);
644   Thread::SetThreadLocal(key, expected);
645   void* actual = Thread::GetExistingThreadLocal(key);
646   if (expected != actual) {
647     V8_Fatal(__FILE__, __LINE__,
648              "V8 failed to initialize fast TLS on current kernel");
649   }
650   Thread::SetThreadLocal(key, NULL);
651 }
652
653 #endif  // V8_FAST_TLS_SUPPORTED
654
655
656 Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
657 #ifdef V8_FAST_TLS_SUPPORTED
658   bool check_fast_tls = false;
659   if (tls_base_offset_initialized == 0) {
660     check_fast_tls = true;
661     InitializeTlsBaseOffset();
662   }
663 #endif
664   pthread_key_t key;
665   int result = pthread_key_create(&key, NULL);
666   ASSERT_EQ(0, result);
667   USE(result);
668   LocalStorageKey local_key = PthreadKeyToLocalKey(key);
669 #ifdef V8_FAST_TLS_SUPPORTED
670   // If we just initialized fast TLS support, make sure it works.
671   if (check_fast_tls) CheckFastTls(local_key);
672 #endif
673   return local_key;
674 }
675
676
677 void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
678   pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
679   int result = pthread_key_delete(pthread_key);
680   ASSERT_EQ(0, result);
681   USE(result);
682 }
683
684
685 void* Thread::GetThreadLocal(LocalStorageKey key) {
686   pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
687   return pthread_getspecific(pthread_key);
688 }
689
690
691 void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
692   pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
693   int result = pthread_setspecific(pthread_key, value);
694   ASSERT_EQ(0, result);
695   USE(result);
696 }
697
698
699 } }  // namespace v8::internal