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 "platform-posix.h" 33 34 #include <dlfcn.h> 35 #include <pthread.h> 36 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) 37 #include <pthread_np.h> // for pthread_set_name_np 38 #endif 39 #include <sched.h> // for sched_yield 40 #include <unistd.h> 41 #include <errno.h> 42 #include <time.h> 43 44 #include <sys/mman.h> 45 #include <sys/socket.h> 46 #include <sys/resource.h> 47 #include <sys/time.h> 48 #include <sys/types.h> 49 #include <sys/stat.h> 50 #if defined(__linux__) 51 #include <sys/prctl.h> // for prctl 52 #endif 53 #if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \ 54 defined(__NetBSD__) || defined(__OpenBSD__) 55 #include <sys/sysctl.h> // for sysctl 56 #endif 57 58 #include <arpa/inet.h> 59 #include <netinet/in.h> 60 #include <netdb.h> 61 62 #undef MAP_TYPE 63 64 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 65 #define LOG_TAG "v8" 66 #include <android/log.h> 67 #endif 68 69 #include "v8.h" 70 71 #include "codegen.h" 72 #include "platform.h" 73 74 namespace v8 { 75 namespace internal { 76 77 // 0 is never a valid thread id. 78 static const pthread_t kNoThread = (pthread_t) 0; 79 80 81 uint64_t OS::CpuFeaturesImpliedByPlatform() { 82 #if defined(__APPLE__) 83 // Mac OS X requires all these to install so we can assume they are present. 84 // These constants are defined by the CPUid instructions. 85 const uint64_t one = 1; 86 return (one << SSE2) | (one << CMOV) | (one << RDTSC) | (one << CPUID); 87 #else 88 return 0; // Nothing special about the other systems. 89 #endif 90 } 91 92 93 // Maximum size of the virtual memory. 0 means there is no artificial 94 // limit. 95 96 intptr_t OS::MaxVirtualMemory() { 97 struct rlimit limit; 98 int result = getrlimit(RLIMIT_DATA, &limit); 99 if (result != 0) return 0; 100 return limit.rlim_cur; 101 } 102 103 104 int OS::ActivationFrameAlignment() { 105 #if V8_TARGET_ARCH_ARM 106 // On EABI ARM targets this is required for fp correctness in the 107 // runtime system. 108 return 8; 109 #elif V8_TARGET_ARCH_MIPS 110 return 8; 111 #else 112 // Otherwise we just assume 16 byte alignment, i.e.: 113 // - With gcc 4.4 the tree vectorization optimizer can generate code 114 // that requires 16 byte alignment such as movdqa on x86. 115 // - Mac OS X and Solaris (64-bit) activation frames must be 16 byte-aligned; 116 // see "Mac OS X ABI Function Call Guide" 117 return 16; 118 #endif 119 } 120 121 122 intptr_t OS::CommitPageSize() { 123 static intptr_t page_size = getpagesize(); 124 return page_size; 125 } 126 127 128 void OS::Free(void* address, const size_t size) { 129 // TODO(1240712): munmap has a return value which is ignored here. 130 int result = munmap(address, size); 131 USE(result); 132 ASSERT(result == 0); 133 } 134 135 136 // Get rid of writable permission on code allocations. 137 void OS::ProtectCode(void* address, const size_t size) { 138 #if defined(__CYGWIN__) 139 DWORD old_protect; 140 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect); 141 #elif defined(__native_client__) 142 // The Native Client port of V8 uses an interpreter, so 143 // code pages don't need PROT_EXEC. 144 mprotect(address, size, PROT_READ); 145 #else 146 mprotect(address, size, PROT_READ | PROT_EXEC); 147 #endif 148 } 149 150 151 // Create guard pages. 152 void OS::Guard(void* address, const size_t size) { 153 #if defined(__CYGWIN__) 154 DWORD oldprotect; 155 VirtualProtect(address, size, PAGE_READONLY | PAGE_GUARD, &oldprotect); 156 #else 157 mprotect(address, size, PROT_NONE); 158 #endif 159 } 160 161 162 void* OS::GetRandomMmapAddr() { 163 #if defined(__native_client__) 164 // TODO(bradchen): restore randomization once Native Client gets 165 // smarter about using mmap address hints. 166 // See http://code.google.com/p/nativeclient/issues/3341 167 return NULL; 168 #endif 169 Isolate* isolate = Isolate::UncheckedCurrent(); 170 // Note that the current isolate isn't set up in a call path via 171 // CpuFeatures::Probe. We don't care about randomization in this case because 172 // the code page is immediately freed. 173 if (isolate != NULL) { 174 #if V8_TARGET_ARCH_X64 175 uint64_t rnd1 = V8::RandomPrivate(isolate); 176 uint64_t rnd2 = V8::RandomPrivate(isolate); 177 uint64_t raw_addr = (rnd1 << 32) ^ rnd2; 178 // Currently available CPUs have 48 bits of virtual addressing. Truncate 179 // the hint address to 46 bits to give the kernel a fighting chance of 180 // fulfilling our placement request. 181 raw_addr &= V8_UINT64_C(0x3ffffffff000); 182 #else 183 uint32_t raw_addr = V8::RandomPrivate(isolate); 184 185 raw_addr &= 0x3ffff000; 186 187 # ifdef __sun 188 // For our Solaris/illumos mmap hint, we pick a random address in the bottom 189 // half of the top half of the address space (that is, the third quarter). 190 // Because we do not MAP_FIXED, this will be treated only as a hint -- the 191 // system will not fail to mmap() because something else happens to already 192 // be mapped at our random address. We deliberately set the hint high enough 193 // to get well above the system's break (that is, the heap); Solaris and 194 // illumos will try the hint and if that fails allocate as if there were 195 // no hint at all. The high hint prevents the break from getting hemmed in 196 // at low values, ceding half of the address space to the system heap. 197 raw_addr += 0x80000000; 198 # else 199 // The range 0x20000000 - 0x60000000 is relatively unpopulated across a 200 // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos 201 // 10.6 and 10.7. 202 raw_addr += 0x20000000; 203 # endif 204 #endif 205 return reinterpret_cast<void*>(raw_addr); 206 } 207 return NULL; 208 } 209 210 211 size_t OS::AllocateAlignment() { 212 return getpagesize(); 213 } 214 215 216 void OS::Sleep(int milliseconds) { 217 useconds_t ms = static_cast<useconds_t>(milliseconds); 218 usleep(1000 * ms); 219 } 220 221 222 int OS::NumberOfCores() { 223 return sysconf(_SC_NPROCESSORS_ONLN); 224 } 225 226 227 void OS::Abort() { 228 // Redirect to std abort to signal abnormal program termination. 229 if (FLAG_break_on_abort) { 230 DebugBreak(); 231 } 232 abort(); 233 } 234 235 236 void OS::DebugBreak() { 237 #if V8_HOST_ARCH_ARM 238 asm("bkpt 0"); 239 #elif V8_HOST_ARCH_MIPS 240 asm("break"); 241 #elif V8_HOST_ARCH_IA32 242 #if defined(__native_client__) 243 asm("hlt"); 244 #else 245 asm("int $3"); 246 #endif // __native_client__ 247 #elif V8_HOST_ARCH_X64 248 asm("int $3"); 249 #else 250 #error Unsupported host architecture. 251 #endif 252 } 253 254 255 // ---------------------------------------------------------------------------- 256 // Math functions 257 258 double ceiling(double x) { 259 // Correct buggy 'ceil' on some systems (i.e. FreeBSD, OS X 10.5) 260 return (-1.0 < x && x < 0.0) ? -0.0 : ceil(x); 261 } 262 263 264 double modulo(double x, double y) { 265 return fmod(x, y); 266 } 267 268 269 #define UNARY_MATH_FUNCTION(name, generator) \ 270 static UnaryMathFunction fast_##name##_function = NULL; \ 271 void init_fast_##name##_function() { \ 272 fast_##name##_function = generator; \ 273 } \ 274 double fast_##name(double x) { \ 275 return (*fast_##name##_function)(x); \ 276 } 277 278 UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN)) 279 UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS)) 280 UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN)) 281 UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG)) 282 UNARY_MATH_FUNCTION(exp, CreateExpFunction()) 283 UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) 284 285 #undef UNARY_MATH_FUNCTION 286 287 288 void lazily_initialize_fast_exp() { 289 if (fast_exp_function == NULL) { 290 init_fast_exp_function(); 291 } 292 } 293 294 295 double OS::nan_value() { 296 // NAN from math.h is defined in C99 and not in POSIX. 297 return NAN; 298 } 299 300 301 int OS::GetCurrentProcessId() { 302 return static_cast<int>(getpid()); 303 } 304 305 306 // ---------------------------------------------------------------------------- 307 // POSIX date/time support. 308 // 309 310 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { 311 struct rusage usage; 312 313 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1; 314 *secs = usage.ru_utime.tv_sec; 315 *usecs = usage.ru_utime.tv_usec; 316 return 0; 317 } 318 319 320 double OS::TimeCurrentMillis() { 321 struct timeval tv; 322 if (gettimeofday(&tv, NULL) < 0) return 0.0; 323 return (static_cast<double>(tv.tv_sec) * 1000) + 324 (static_cast<double>(tv.tv_usec) / 1000); 325 } 326 327 328 int64_t OS::Ticks() { 329 // gettimeofday has microsecond resolution. 330 struct timeval tv; 331 if (gettimeofday(&tv, NULL) < 0) 332 return 0; 333 return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec; 334 } 335 336 337 double OS::DaylightSavingsOffset(double time) { 338 if (std::isnan(time)) return nan_value(); 339 time_t tv = static_cast<time_t>(floor(time/msPerSecond)); 340 struct tm* t = localtime(&tv); 341 if (NULL == t) return nan_value(); 342 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0; 343 } 344 345 346 int OS::GetLastError() { 347 return errno; 348 } 349 350 351 // ---------------------------------------------------------------------------- 352 // POSIX stdio support. 353 // 354 355 FILE* OS::FOpen(const char* path, const char* mode) { 356 FILE* file = fopen(path, mode); 357 if (file == NULL) return NULL; 358 struct stat file_stat; 359 if (fstat(fileno(file), &file_stat) != 0) return NULL; 360 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0); 361 if (is_regular_file) return file; 362 fclose(file); 363 return NULL; 364 } 365 366 367 bool OS::Remove(const char* path) { 368 return (remove(path) == 0); 369 } 370 371 372 FILE* OS::OpenTemporaryFile() { 373 return tmpfile(); 374 } 375 376 377 const char* const OS::LogFileOpenMode = "w"; 378 379 380 void OS::Print(const char* format, ...) { 381 va_list args; 382 va_start(args, format); 383 VPrint(format, args); 384 va_end(args); 385 } 386 387 388 void OS::VPrint(const char* format, va_list args) { 389 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 390 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 391 #else 392 vprintf(format, args); 393 #endif 394 } 395 396 397 void OS::FPrint(FILE* out, const char* format, ...) { 398 va_list args; 399 va_start(args, format); 400 VFPrint(out, format, args); 401 va_end(args); 402 } 403 404 405 void OS::VFPrint(FILE* out, const char* format, va_list args) { 406 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 407 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 408 #else 409 vfprintf(out, format, args); 410 #endif 411 } 412 413 414 void OS::PrintError(const char* format, ...) { 415 va_list args; 416 va_start(args, format); 417 VPrintError(format, args); 418 va_end(args); 419 } 420 421 422 void OS::VPrintError(const char* format, va_list args) { 423 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 424 __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args); 425 #else 426 vfprintf(stderr, format, args); 427 #endif 428 } 429 430 431 int OS::SNPrintF(Vector<char> str, const char* format, ...) { 432 va_list args; 433 va_start(args, format); 434 int result = VSNPrintF(str, format, args); 435 va_end(args); 436 return result; 437 } 438 439 440 int OS::VSNPrintF(Vector<char> str, 441 const char* format, 442 va_list args) { 443 int n = vsnprintf(str.start(), str.length(), format, args); 444 if (n < 0 || n >= str.length()) { 445 // If the length is zero, the assignment fails. 446 if (str.length() > 0) 447 str[str.length() - 1] = '\0'; 448 return -1; 449 } else { 450 return n; 451 } 452 } 453 454 455 #if V8_TARGET_ARCH_IA32 456 static void MemMoveWrapper(void* dest, const void* src, size_t size) { 457 memmove(dest, src, size); 458 } 459 460 461 // Initialize to library version so we can call this at any time during startup. 462 static OS::MemMoveFunction memmove_function = &MemMoveWrapper; 463 464 // Defined in codegen-ia32.cc. 465 OS::MemMoveFunction CreateMemMoveFunction(); 466 467 // Copy memory area. No restrictions. 468 void OS::MemMove(void* dest, const void* src, size_t size) { 469 if (size == 0) return; 470 // Note: here we rely on dependent reads being ordered. This is true 471 // on all architectures we currently support. 472 (*memmove_function)(dest, src, size); 473 } 474 475 #elif defined(V8_HOST_ARCH_ARM) 476 void OS::MemCopyUint16Uint8Wrapper(uint16_t* dest, 477 const uint8_t* src, 478 size_t chars) { 479 uint16_t *limit = dest + chars; 480 while (dest < limit) { 481 *dest++ = static_cast<uint16_t>(*src++); 482 } 483 } 484 485 486 OS::MemCopyUint8Function OS::memcopy_uint8_function = &OS::MemCopyUint8Wrapper; 487 OS::MemCopyUint16Uint8Function OS::memcopy_uint16_uint8_function = 488 &OS::MemCopyUint16Uint8Wrapper; 489 // Defined in codegen-arm.cc. 490 OS::MemCopyUint8Function CreateMemCopyUint8Function( 491 OS::MemCopyUint8Function stub); 492 OS::MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function( 493 OS::MemCopyUint16Uint8Function stub); 494 #endif 495 496 497 void OS::PostSetUp() { 498 #if V8_TARGET_ARCH_IA32 499 OS::MemMoveFunction generated_memmove = CreateMemMoveFunction(); 500 if (generated_memmove != NULL) { 501 memmove_function = generated_memmove; 502 } 503 #elif defined(V8_HOST_ARCH_ARM) 504 OS::memcopy_uint8_function = 505 CreateMemCopyUint8Function(&OS::MemCopyUint8Wrapper); 506 OS::memcopy_uint16_uint8_function = 507 CreateMemCopyUint16Uint8Function(&OS::MemCopyUint16Uint8Wrapper); 508 #endif 509 init_fast_sin_function(); 510 init_fast_cos_function(); 511 init_fast_tan_function(); 512 init_fast_log_function(); 513 // fast_exp is initialized lazily. 514 init_fast_sqrt_function(); 515 } 516 517 518 // ---------------------------------------------------------------------------- 519 // POSIX string support. 520 // 521 522 char* OS::StrChr(char* str, int c) { 523 return strchr(str, c); 524 } 525 526 527 void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) { 528 strncpy(dest.start(), src, n); 529 } 530 531 532 // ---------------------------------------------------------------------------- 533 // POSIX thread support. 534 // 535 536 class Thread::PlatformData : public Malloced { 537 public: 538 PlatformData() : thread_(kNoThread) {} 539 pthread_t thread_; // Thread handle for pthread. 540 }; 541 542 Thread::Thread(const Options& options) 543 : data_(new PlatformData), 544 stack_size_(options.stack_size()), 545 start_semaphore_(NULL) { 546 set_name(options.name()); 547 } 548 549 550 Thread::~Thread() { 551 delete data_; 552 } 553 554 555 static void SetThreadName(const char* name) { 556 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) 557 pthread_set_name_np(pthread_self(), name); 558 #elif defined(__NetBSD__) 559 STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP); 560 pthread_setname_np(pthread_self(), "%s", name); 561 #elif defined(__APPLE__) 562 // pthread_setname_np is only available in 10.6 or later, so test 563 // for it at runtime. 564 int (*dynamic_pthread_setname_np)(const char*); 565 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) = 566 dlsym(RTLD_DEFAULT, "pthread_setname_np"); 567 if (dynamic_pthread_setname_np == NULL) 568 return; 569 570 // Mac OS X does not expose the length limit of the name, so hardcode it. 571 static const int kMaxNameLength = 63; 572 STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength); 573 dynamic_pthread_setname_np(name); 574 #elif defined(PR_SET_NAME) 575 prctl(PR_SET_NAME, 576 reinterpret_cast<unsigned long>(name), // NOLINT 577 0, 0, 0); 578 #endif 579 } 580 581 582 static void* ThreadEntry(void* arg) { 583 Thread* thread = reinterpret_cast<Thread*>(arg); 584 // This is also initialized by the first argument to pthread_create() but we 585 // don't know which thread will run first (the original thread or the new 586 // one) so we initialize it here too. 587 thread->data()->thread_ = pthread_self(); 588 SetThreadName(thread->name()); 589 ASSERT(thread->data()->thread_ != kNoThread); 590 thread->NotifyStartedAndRun(); 591 return NULL; 592 } 593 594 595 void Thread::set_name(const char* name) { 596 strncpy(name_, name, sizeof(name_)); 597 name_[sizeof(name_) - 1] = '\0'; 598 } 599 600 601 void Thread::Start() { 602 int result; 603 pthread_attr_t attr; 604 memset(&attr, 0, sizeof(attr)); 605 result = pthread_attr_init(&attr); 606 ASSERT_EQ(0, result); 607 // Native client uses default stack size. 608 #if !defined(__native_client__) 609 if (stack_size_ > 0) { 610 result = pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_)); 611 ASSERT_EQ(0, result); 612 } 613 #endif 614 result = pthread_create(&data_->thread_, &attr, ThreadEntry, this); 615 ASSERT_EQ(0, result); 616 result = pthread_attr_destroy(&attr); 617 ASSERT_EQ(0, result); 618 ASSERT(data_->thread_ != kNoThread); 619 USE(result); 620 } 621 622 623 void Thread::Join() { 624 pthread_join(data_->thread_, NULL); 625 } 626 627 628 void Thread::YieldCPU() { 629 int result = sched_yield(); 630 ASSERT_EQ(0, result); 631 USE(result); 632 } 633 634 635 static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) { 636 #if defined(__CYGWIN__) 637 // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps 638 // because pthread_key_t is a pointer type on Cygwin. This will probably not 639 // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway. 640 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t)); 641 intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key); 642 return static_cast<Thread::LocalStorageKey>(ptr_key); 643 #else 644 return static_cast<Thread::LocalStorageKey>(pthread_key); 645 #endif 646 } 647 648 649 static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) { 650 #if defined(__CYGWIN__) 651 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t)); 652 intptr_t ptr_key = static_cast<intptr_t>(local_key); 653 return reinterpret_cast<pthread_key_t>(ptr_key); 654 #else 655 return static_cast<pthread_key_t>(local_key); 656 #endif 657 } 658 659 660 #ifdef V8_FAST_TLS_SUPPORTED 661 662 static Atomic32 tls_base_offset_initialized = 0; 663 intptr_t kMacTlsBaseOffset = 0; 664 665 // It's safe to do the initialization more that once, but it has to be 666 // done at least once. 667 static void InitializeTlsBaseOffset() { 668 const size_t kBufferSize = 128; 669 char buffer[kBufferSize]; 670 size_t buffer_size = kBufferSize; 671 int ctl_name[] = { CTL_KERN , KERN_OSRELEASE }; 672 if (sysctl(ctl_name, 2, buffer, &buffer_size, NULL, 0) != 0) { 673 V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version"); 674 } 675 // The buffer now contains a string of the form XX.YY.ZZ, where 676 // XX is the major kernel version component. 677 // Make sure the buffer is 0-terminated. 678 buffer[kBufferSize - 1] = '\0'; 679 char* period_pos = strchr(buffer, '.'); 680 *period_pos = '\0'; 681 int kernel_version_major = 682 static_cast<int>(strtol(buffer, NULL, 10)); // NOLINT 683 // The constants below are taken from pthreads.s from the XNU kernel 684 // sources archive at www.opensource.apple.com. 685 if (kernel_version_major < 11) { 686 // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the 687 // same offsets. 688 #if V8_HOST_ARCH_IA32 689 kMacTlsBaseOffset = 0x48; 690 #else 691 kMacTlsBaseOffset = 0x60; 692 #endif 693 } else { 694 // 11.x.x (Lion) changed the offset. 695 kMacTlsBaseOffset = 0; 696 } 697 698 Release_Store(&tls_base_offset_initialized, 1); 699 } 700 701 702 static void CheckFastTls(Thread::LocalStorageKey key) { 703 void* expected = reinterpret_cast<void*>(0x1234CAFE); 704 Thread::SetThreadLocal(key, expected); 705 void* actual = Thread::GetExistingThreadLocal(key); 706 if (expected != actual) { 707 V8_Fatal(__FILE__, __LINE__, 708 "V8 failed to initialize fast TLS on current kernel"); 709 } 710 Thread::SetThreadLocal(key, NULL); 711 } 712 713 #endif // V8_FAST_TLS_SUPPORTED 714 715 716 Thread::LocalStorageKey Thread::CreateThreadLocalKey() { 717 #ifdef V8_FAST_TLS_SUPPORTED 718 bool check_fast_tls = false; 719 if (tls_base_offset_initialized == 0) { 720 check_fast_tls = true; 721 InitializeTlsBaseOffset(); 722 } 723 #endif 724 pthread_key_t key; 725 int result = pthread_key_create(&key, NULL); 726 ASSERT_EQ(0, result); 727 USE(result); 728 LocalStorageKey local_key = PthreadKeyToLocalKey(key); 729 #ifdef V8_FAST_TLS_SUPPORTED 730 // If we just initialized fast TLS support, make sure it works. 731 if (check_fast_tls) CheckFastTls(local_key); 732 #endif 733 return local_key; 734 } 735 736 737 void Thread::DeleteThreadLocalKey(LocalStorageKey key) { 738 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 739 int result = pthread_key_delete(pthread_key); 740 ASSERT_EQ(0, result); 741 USE(result); 742 } 743 744 745 void* Thread::GetThreadLocal(LocalStorageKey key) { 746 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 747 return pthread_getspecific(pthread_key); 748 } 749 750 751 void Thread::SetThreadLocal(LocalStorageKey key, void* value) { 752 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 753 int result = pthread_setspecific(pthread_key, value); 754 ASSERT_EQ(0, result); 755 USE(result); 756 } 757 758 759 class POSIXMutex : public Mutex { 760 public: 761 POSIXMutex() { 762 pthread_mutexattr_t attr; 763 memset(&attr, 0, sizeof(attr)); 764 int result = pthread_mutexattr_init(&attr); 765 ASSERT(result == 0); 766 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 767 ASSERT(result == 0); 768 result = pthread_mutex_init(&mutex_, &attr); 769 ASSERT(result == 0); 770 result = pthread_mutexattr_destroy(&attr); 771 ASSERT(result == 0); 772 USE(result); 773 } 774 775 virtual ~POSIXMutex() { pthread_mutex_destroy(&mutex_); } 776 777 virtual int Lock() { return pthread_mutex_lock(&mutex_); } 778 779 virtual int Unlock() { return pthread_mutex_unlock(&mutex_); } 780 781 virtual bool TryLock() { 782 int result = pthread_mutex_trylock(&mutex_); 783 // Return false if the lock is busy and locking failed. 784 if (result == EBUSY) { 785 return false; 786 } 787 ASSERT(result == 0); // Verify no other errors. 788 return true; 789 } 790 791 private: 792 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms. 793 }; 794 795 796 Mutex* OS::CreateMutex() { 797 return new POSIXMutex(); 798 } 799 800 801 // ---------------------------------------------------------------------------- 802 // POSIX socket support. 803 // 804 805 class POSIXSocket : public Socket { 806 public: 807 explicit POSIXSocket() { 808 // Create the socket. 809 socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 810 if (IsValid()) { 811 // Allow rapid reuse. 812 static const int kOn = 1; 813 int ret = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, 814 &kOn, sizeof(kOn)); 815 ASSERT(ret == 0); 816 USE(ret); 817 } 818 } 819 explicit POSIXSocket(int socket): socket_(socket) { } 820 virtual ~POSIXSocket() { Shutdown(); } 821 822 // Server initialization. 823 bool Bind(const int port); 824 bool Listen(int backlog) const; 825 Socket* Accept() const; 826 827 // Client initialization. 828 bool Connect(const char* host, const char* port); 829 830 // Shutdown socket for both read and write. 831 bool Shutdown(); 832 833 // Data Transimission 834 int Send(const char* data, int len) const; 835 int Receive(char* data, int len) const; 836 837 bool SetReuseAddress(bool reuse_address); 838 839 bool IsValid() const { return socket_ != -1; } 840 841 private: 842 int socket_; 843 }; 844 845 846 bool POSIXSocket::Bind(const int port) { 847 if (!IsValid()) { 848 return false; 849 } 850 851 sockaddr_in addr; 852 memset(&addr, 0, sizeof(addr)); 853 addr.sin_family = AF_INET; 854 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 855 addr.sin_port = htons(port); 856 int status = bind(socket_, 857 BitCast<struct sockaddr *>(&addr), 858 sizeof(addr)); 859 return status == 0; 860 } 861 862 863 bool POSIXSocket::Listen(int backlog) const { 864 if (!IsValid()) { 865 return false; 866 } 867 868 int status = listen(socket_, backlog); 869 return status == 0; 870 } 871 872 873 Socket* POSIXSocket::Accept() const { 874 if (!IsValid()) { 875 return NULL; 876 } 877 878 int socket; 879 do { 880 socket = accept(socket_, NULL, NULL); 881 } while (socket == -1 && errno == EINTR); 882 883 if (socket == -1) { 884 return NULL; 885 } else { 886 return new POSIXSocket(socket); 887 } 888 } 889 890 891 bool POSIXSocket::Connect(const char* host, const char* port) { 892 if (!IsValid()) { 893 return false; 894 } 895 896 // Lookup host and port. 897 struct addrinfo *result = NULL; 898 struct addrinfo hints; 899 memset(&hints, 0, sizeof(addrinfo)); 900 hints.ai_family = AF_INET; 901 hints.ai_socktype = SOCK_STREAM; 902 hints.ai_protocol = IPPROTO_TCP; 903 int status = getaddrinfo(host, port, &hints, &result); 904 if (status != 0) { 905 return false; 906 } 907 908 // Connect. 909 do { 910 status = connect(socket_, result->ai_addr, result->ai_addrlen); 911 } while (status == -1 && errno == EINTR); 912 freeaddrinfo(result); 913 return status == 0; 914 } 915 916 917 bool POSIXSocket::Shutdown() { 918 if (IsValid()) { 919 // Shutdown socket for both read and write. 920 int status = shutdown(socket_, SHUT_RDWR); 921 close(socket_); 922 socket_ = -1; 923 return status == 0; 924 } 925 return true; 926 } 927 928 929 int POSIXSocket::Send(const char* data, int len) const { 930 if (len <= 0) return 0; 931 int written = 0; 932 while (written < len) { 933 int status = send(socket_, data + written, len - written, 0); 934 if (status == 0) { 935 break; 936 } else if (status > 0) { 937 written += status; 938 } else if (errno != EINTR) { 939 return 0; 940 } 941 } 942 return written; 943 } 944 945 946 int POSIXSocket::Receive(char* data, int len) const { 947 if (len <= 0) return 0; 948 int status; 949 do { 950 status = recv(socket_, data, len, 0); 951 } while (status == -1 && errno == EINTR); 952 return (status < 0) ? 0 : status; 953 } 954 955 956 bool POSIXSocket::SetReuseAddress(bool reuse_address) { 957 int on = reuse_address ? 1 : 0; 958 int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 959 return status == 0; 960 } 961 962 963 bool Socket::SetUp() { 964 // Nothing to do on POSIX. 965 return true; 966 } 967 968 969 int Socket::LastError() { 970 return errno; 971 } 972 973 974 uint16_t Socket::HToN(uint16_t value) { 975 return htons(value); 976 } 977 978 979 uint16_t Socket::NToH(uint16_t value) { 980 return ntohs(value); 981 } 982 983 984 uint32_t Socket::HToN(uint32_t value) { 985 return htonl(value); 986 } 987 988 989 uint32_t Socket::NToH(uint32_t value) { 990 return ntohl(value); 991 } 992 993 994 Socket* OS::CreateSocket() { 995 return new POSIXSocket(); 996 } 997 998 999 } } // namespace v8::internal 1000