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 74namespace v8 { 75namespace internal { 76 77// 0 is never a valid thread id. 78static const pthread_t kNoThread = (pthread_t) 0; 79 80 81uint64_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 96intptr_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 104int 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 122intptr_t OS::CommitPageSize() { 123 static intptr_t page_size = getpagesize(); 124 return page_size; 125} 126 127 128void 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. 137void 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. 152void 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 162void* 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 211size_t OS::AllocateAlignment() { 212 return getpagesize(); 213} 214 215 216void OS::Sleep(int milliseconds) { 217 useconds_t ms = static_cast<useconds_t>(milliseconds); 218 usleep(1000 * ms); 219} 220 221 222int OS::NumberOfCores() { 223 return sysconf(_SC_NPROCESSORS_ONLN); 224} 225 226 227void 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 236void 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 258double 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 264double modulo(double x, double y) { 265 return fmod(x, y); 266} 267 268 269#define UNARY_MATH_FUNCTION(name, generator) \ 270static UnaryMathFunction fast_##name##_function = NULL; \ 271void init_fast_##name##_function() { \ 272 fast_##name##_function = generator; \ 273} \ 274double fast_##name(double x) { \ 275 return (*fast_##name##_function)(x); \ 276} 277 278UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN)) 279UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS)) 280UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN)) 281UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG)) 282UNARY_MATH_FUNCTION(exp, CreateExpFunction()) 283UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) 284 285#undef UNARY_MATH_FUNCTION 286 287 288void lazily_initialize_fast_exp() { 289 if (fast_exp_function == NULL) { 290 init_fast_exp_function(); 291 } 292} 293 294 295double OS::nan_value() { 296 // NAN from math.h is defined in C99 and not in POSIX. 297 return NAN; 298} 299 300 301int OS::GetCurrentProcessId() { 302 return static_cast<int>(getpid()); 303} 304 305 306// ---------------------------------------------------------------------------- 307// POSIX date/time support. 308// 309 310int 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 320double 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 328int64_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 337double 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 346int OS::GetLastError() { 347 return errno; 348} 349 350 351// ---------------------------------------------------------------------------- 352// POSIX stdio support. 353// 354 355FILE* 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 367bool OS::Remove(const char* path) { 368 return (remove(path) == 0); 369} 370 371 372FILE* OS::OpenTemporaryFile() { 373 return tmpfile(); 374} 375 376 377const char* const OS::LogFileOpenMode = "w"; 378 379 380void 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 388void 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 397void 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 405void 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 414void 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 422void 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 431int 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 440int 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 456static 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. 462static OS::MemMoveFunction memmove_function = &MemMoveWrapper; 463 464// Defined in codegen-ia32.cc. 465OS::MemMoveFunction CreateMemMoveFunction(); 466 467// Copy memory area. No restrictions. 468void 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) 476void 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 486OS::MemCopyUint8Function OS::memcopy_uint8_function = &OS::MemCopyUint8Wrapper; 487OS::MemCopyUint16Uint8Function OS::memcopy_uint16_uint8_function = 488 &OS::MemCopyUint16Uint8Wrapper; 489// Defined in codegen-arm.cc. 490OS::MemCopyUint8Function CreateMemCopyUint8Function( 491 OS::MemCopyUint8Function stub); 492OS::MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function( 493 OS::MemCopyUint16Uint8Function stub); 494#endif 495 496 497void 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 522char* OS::StrChr(char* str, int c) { 523 return strchr(str, c); 524} 525 526 527void 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 536class Thread::PlatformData : public Malloced { 537 public: 538 PlatformData() : thread_(kNoThread) {} 539 pthread_t thread_; // Thread handle for pthread. 540}; 541 542Thread::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 550Thread::~Thread() { 551 delete data_; 552} 553 554 555static 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 582static 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 595void Thread::set_name(const char* name) { 596 strncpy(name_, name, sizeof(name_)); 597 name_[sizeof(name_) - 1] = '\0'; 598} 599 600 601void 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 623void Thread::Join() { 624 pthread_join(data_->thread_, NULL); 625} 626 627 628void Thread::YieldCPU() { 629 int result = sched_yield(); 630 ASSERT_EQ(0, result); 631 USE(result); 632} 633 634 635static 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 649static 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 662static Atomic32 tls_base_offset_initialized = 0; 663intptr_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. 667static 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 702static 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 716Thread::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 737void 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 745void* Thread::GetThreadLocal(LocalStorageKey key) { 746 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 747 return pthread_getspecific(pthread_key); 748} 749 750 751void 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 759class 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 796Mutex* OS::CreateMutex() { 797 return new POSIXMutex(); 798} 799 800 801// ---------------------------------------------------------------------------- 802// POSIX socket support. 803// 804 805class 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 846bool 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 863bool 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 873Socket* 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 891bool 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 917bool 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 929int 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 946int 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 956bool 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 963bool Socket::SetUp() { 964 // Nothing to do on POSIX. 965 return true; 966} 967 968 969int Socket::LastError() { 970 return errno; 971} 972 973 974uint16_t Socket::HToN(uint16_t value) { 975 return htons(value); 976} 977 978 979uint16_t Socket::NToH(uint16_t value) { 980 return ntohs(value); 981} 982 983 984uint32_t Socket::HToN(uint32_t value) { 985 return htonl(value); 986} 987 988 989uint32_t Socket::NToH(uint32_t value) { 990 return ntohl(value); 991} 992 993 994Socket* OS::CreateSocket() { 995 return new POSIXSocket(); 996} 997 998 999} } // namespace v8::internal 1000