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