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