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