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