1 // Copyright 2006-2008 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 Linux goes here. For the POSIX comaptible parts 29 // the implementation is in platform-posix.cc. 30 31 #include <pthread.h> 32 #include <semaphore.h> 33 #include <signal.h> 34 #include <sys/time.h> 35 #include <sys/resource.h> 36 #include <sys/types.h> 37 #include <stdlib.h> 38 39 // Ubuntu Dapper requires memory pages to be marked as 40 // executable. Otherwise, OS raises an exception when executing code 41 // in that page. 42 #include <sys/types.h> // mmap & munmap 43 #include <sys/mman.h> // mmap & munmap 44 #include <sys/stat.h> // open 45 #include <fcntl.h> // open 46 #include <unistd.h> // sysconf 47 #ifdef __GLIBC__ 48 #include <execinfo.h> // backtrace, backtrace_symbols 49 #endif // def __GLIBC__ 50 #include <strings.h> // index 51 #include <errno.h> 52 #include <stdarg.h> 53 54 #undef MAP_TYPE 55 56 #include "v8.h" 57 58 #include "platform.h" 59 #include "top.h" 60 #include "v8threads.h" 61 62 63 namespace v8 { 64 namespace internal { 65 66 // 0 is never a valid thread id on Linux since tids and pids share a 67 // name space and pid 0 is reserved (see man 2 kill). 68 static const pthread_t kNoThread = (pthread_t) 0; 69 70 71 double ceiling(double x) { 72 return ceil(x); 73 } 74 75 76 void OS::Setup() { 77 // Seed the random number generator. 78 // Convert the current time to a 64-bit integer first, before converting it 79 // to an unsigned. Going directly can cause an overflow and the seed to be 80 // set to all ones. The seed will be identical for different instances that 81 // call this setup code within the same millisecond. 82 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); 83 srandom(static_cast<unsigned int>(seed)); 84 } 85 86 87 uint64_t OS::CpuFeaturesImpliedByPlatform() { 88 #if (defined(__VFP_FP__) && !defined(__SOFTFP__)) 89 // Here gcc is telling us that we are on an ARM and gcc is assuming that we 90 // have VFP3 instructions. If gcc can assume it then so can we. 91 return 1u << VFP3; 92 #elif CAN_USE_ARMV7_INSTRUCTIONS 93 return 1u << ARMv7; 94 #else 95 return 0; // Linux runs on anything. 96 #endif 97 } 98 99 100 #ifdef __arm__ 101 bool OS::ArmCpuHasFeature(CpuFeature feature) { 102 const char* search_string = NULL; 103 const char* file_name = "/proc/cpuinfo"; 104 // Simple detection of VFP at runtime for Linux. 105 // It is based on /proc/cpuinfo, which reveals hardware configuration 106 // to user-space applications. According to ARM (mid 2009), no similar 107 // facility is universally available on the ARM architectures, 108 // so it's up to individual OSes to provide such. 109 // 110 // This is written as a straight shot one pass parser 111 // and not using STL string and ifstream because, 112 // on Linux, it's reading from a (non-mmap-able) 113 // character special device. 114 switch (feature) { 115 case VFP3: 116 search_string = "vfp"; 117 break; 118 case ARMv7: 119 search_string = "ARMv7"; 120 break; 121 default: 122 UNREACHABLE(); 123 } 124 125 FILE* f = NULL; 126 const char* what = search_string; 127 128 if (NULL == (f = fopen(file_name, "r"))) 129 return false; 130 131 int k; 132 while (EOF != (k = fgetc(f))) { 133 if (k == *what) { 134 ++what; 135 while ((*what != '\0') && (*what == fgetc(f))) { 136 ++what; 137 } 138 if (*what == '\0') { 139 fclose(f); 140 return true; 141 } else { 142 what = search_string; 143 } 144 } 145 } 146 fclose(f); 147 148 // Did not find string in the proc file. 149 return false; 150 } 151 #endif // def __arm__ 152 153 154 int OS::ActivationFrameAlignment() { 155 #ifdef V8_TARGET_ARCH_ARM 156 // On EABI ARM targets this is required for fp correctness in the 157 // runtime system. 158 return 8; 159 #elif V8_TARGET_ARCH_MIPS 160 return 8; 161 #endif 162 // With gcc 4.4 the tree vectorization optimiser can generate code 163 // that requires 16 byte alignment such as movdqa on x86. 164 return 16; 165 } 166 167 168 const char* OS::LocalTimezone(double time) { 169 if (isnan(time)) return ""; 170 time_t tv = static_cast<time_t>(floor(time/msPerSecond)); 171 struct tm* t = localtime(&tv); 172 if (NULL == t) return ""; 173 return t->tm_zone; 174 } 175 176 177 double OS::LocalTimeOffset() { 178 time_t tv = time(NULL); 179 struct tm* t = localtime(&tv); 180 // tm_gmtoff includes any daylight savings offset, so subtract it. 181 return static_cast<double>(t->tm_gmtoff * msPerSecond - 182 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0)); 183 } 184 185 186 // We keep the lowest and highest addresses mapped as a quick way of 187 // determining that pointers are outside the heap (used mostly in assertions 188 // and verification). The estimate is conservative, ie, not all addresses in 189 // 'allocated' space are actually allocated to our heap. The range is 190 // [lowest, highest), inclusive on the low and and exclusive on the high end. 191 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); 192 static void* highest_ever_allocated = reinterpret_cast<void*>(0); 193 194 195 static void UpdateAllocatedSpaceLimits(void* address, int size) { 196 lowest_ever_allocated = Min(lowest_ever_allocated, address); 197 highest_ever_allocated = 198 Max(highest_ever_allocated, 199 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); 200 } 201 202 203 bool OS::IsOutsideAllocatedSpace(void* address) { 204 return address < lowest_ever_allocated || address >= highest_ever_allocated; 205 } 206 207 208 size_t OS::AllocateAlignment() { 209 return sysconf(_SC_PAGESIZE); 210 } 211 212 213 void* OS::Allocate(const size_t requested, 214 size_t* allocated, 215 bool is_executable) { 216 const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE)); 217 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); 218 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 219 if (mbase == MAP_FAILED) { 220 LOG(StringEvent("OS::Allocate", "mmap failed")); 221 return NULL; 222 } 223 *allocated = msize; 224 UpdateAllocatedSpaceLimits(mbase, msize); 225 return mbase; 226 } 227 228 229 void OS::Free(void* address, const size_t size) { 230 // TODO(1240712): munmap has a return value which is ignored here. 231 int result = munmap(address, size); 232 USE(result); 233 ASSERT(result == 0); 234 } 235 236 237 #ifdef ENABLE_HEAP_PROTECTION 238 239 void OS::Protect(void* address, size_t size) { 240 // TODO(1240712): mprotect has a return value which is ignored here. 241 mprotect(address, size, PROT_READ); 242 } 243 244 245 void OS::Unprotect(void* address, size_t size, bool is_executable) { 246 // TODO(1240712): mprotect has a return value which is ignored here. 247 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); 248 mprotect(address, size, prot); 249 } 250 251 #endif 252 253 254 void OS::Sleep(int milliseconds) { 255 unsigned int ms = static_cast<unsigned int>(milliseconds); 256 usleep(1000 * ms); 257 } 258 259 260 void OS::Abort() { 261 // Redirect to std abort to signal abnormal program termination. 262 abort(); 263 } 264 265 266 void OS::DebugBreak() { 267 // TODO(lrn): Introduce processor define for runtime system (!= V8_ARCH_x, 268 // which is the architecture of generated code). 269 #if (defined(__arm__) || defined(__thumb__)) && \ 270 defined(CAN_USE_ARMV5_INSTRUCTIONS) 271 asm("bkpt 0"); 272 #elif defined(__mips__) 273 asm("break"); 274 #else 275 asm("int $3"); 276 #endif 277 } 278 279 280 class PosixMemoryMappedFile : public OS::MemoryMappedFile { 281 public: 282 PosixMemoryMappedFile(FILE* file, void* memory, int size) 283 : file_(file), memory_(memory), size_(size) { } 284 virtual ~PosixMemoryMappedFile(); 285 virtual void* memory() { return memory_; } 286 private: 287 FILE* file_; 288 void* memory_; 289 int size_; 290 }; 291 292 293 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size, 294 void* initial) { 295 FILE* file = fopen(name, "w+"); 296 if (file == NULL) return NULL; 297 int result = fwrite(initial, size, 1, file); 298 if (result < 1) { 299 fclose(file); 300 return NULL; 301 } 302 void* memory = 303 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0); 304 return new PosixMemoryMappedFile(file, memory, size); 305 } 306 307 308 PosixMemoryMappedFile::~PosixMemoryMappedFile() { 309 if (memory_) munmap(memory_, size_); 310 fclose(file_); 311 } 312 313 314 void OS::LogSharedLibraryAddresses() { 315 #ifdef ENABLE_LOGGING_AND_PROFILING 316 // This function assumes that the layout of the file is as follows: 317 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name] 318 // If we encounter an unexpected situation we abort scanning further entries. 319 FILE* fp = fopen("/proc/self/maps", "r"); 320 if (fp == NULL) return; 321 322 // Allocate enough room to be able to store a full file name. 323 const int kLibNameLen = FILENAME_MAX + 1; 324 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen)); 325 326 // This loop will terminate once the scanning hits an EOF. 327 while (true) { 328 uintptr_t start, end; 329 char attr_r, attr_w, attr_x, attr_p; 330 // Parse the addresses and permission bits at the beginning of the line. 331 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break; 332 if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break; 333 334 int c; 335 if (attr_r == 'r' && attr_x == 'x') { 336 // Found a readable and executable entry. Skip characters until we reach 337 // the beginning of the filename or the end of the line. 338 do { 339 c = getc(fp); 340 } while ((c != EOF) && (c != '\n') && (c != '/')); 341 if (c == EOF) break; // EOF: Was unexpected, just exit. 342 343 // Process the filename if found. 344 if (c == '/') { 345 ungetc(c, fp); // Push the '/' back into the stream to be read below. 346 347 // Read to the end of the line. Exit if the read fails. 348 if (fgets(lib_name, kLibNameLen, fp) == NULL) break; 349 350 // Drop the newline character read by fgets. We do not need to check 351 // for a zero-length string because we know that we at least read the 352 // '/' character. 353 lib_name[strlen(lib_name) - 1] = '\0'; 354 } else { 355 // No library name found, just record the raw address range. 356 snprintf(lib_name, kLibNameLen, 357 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end); 358 } 359 LOG(SharedLibraryEvent(lib_name, start, end)); 360 } else { 361 // Entry not describing executable data. Skip to end of line to setup 362 // reading the next entry. 363 do { 364 c = getc(fp); 365 } while ((c != EOF) && (c != '\n')); 366 if (c == EOF) break; 367 } 368 } 369 free(lib_name); 370 fclose(fp); 371 #endif 372 } 373 374 375 int OS::StackWalk(Vector<OS::StackFrame> frames) { 376 // backtrace is a glibc extension. 377 #ifdef __GLIBC__ 378 int frames_size = frames.length(); 379 void** addresses = NewArray<void*>(frames_size); 380 381 int frames_count = backtrace(addresses, frames_size); 382 383 char** symbols; 384 symbols = backtrace_symbols(addresses, frames_count); 385 if (symbols == NULL) { 386 DeleteArray(addresses); 387 return kStackWalkError; 388 } 389 390 for (int i = 0; i < frames_count; i++) { 391 frames[i].address = addresses[i]; 392 // Format a text representation of the frame based on the information 393 // available. 394 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen), 395 "%s", 396 symbols[i]); 397 // Make sure line termination is in place. 398 frames[i].text[kStackWalkMaxTextLen - 1] = '\0'; 399 } 400 401 DeleteArray(addresses); 402 free(symbols); 403 404 return frames_count; 405 #else // ndef __GLIBC__ 406 return 0; 407 #endif // ndef __GLIBC__ 408 } 409 410 411 // Constants used for mmap. 412 static const int kMmapFd = -1; 413 static const int kMmapFdOffset = 0; 414 415 416 VirtualMemory::VirtualMemory(size_t size) { 417 address_ = mmap(NULL, size, PROT_NONE, 418 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, 419 kMmapFd, kMmapFdOffset); 420 size_ = size; 421 } 422 423 424 VirtualMemory::~VirtualMemory() { 425 if (IsReserved()) { 426 if (0 == munmap(address(), size())) address_ = MAP_FAILED; 427 } 428 } 429 430 431 bool VirtualMemory::IsReserved() { 432 return address_ != MAP_FAILED; 433 } 434 435 436 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { 437 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); 438 if (MAP_FAILED == mmap(address, size, prot, 439 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 440 kMmapFd, kMmapFdOffset)) { 441 return false; 442 } 443 444 UpdateAllocatedSpaceLimits(address, size); 445 return true; 446 } 447 448 449 bool VirtualMemory::Uncommit(void* address, size_t size) { 450 return mmap(address, size, PROT_NONE, 451 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED, 452 kMmapFd, kMmapFdOffset) != MAP_FAILED; 453 } 454 455 456 class ThreadHandle::PlatformData : public Malloced { 457 public: 458 explicit PlatformData(ThreadHandle::Kind kind) { 459 Initialize(kind); 460 } 461 462 void Initialize(ThreadHandle::Kind kind) { 463 switch (kind) { 464 case ThreadHandle::SELF: thread_ = pthread_self(); break; 465 case ThreadHandle::INVALID: thread_ = kNoThread; break; 466 } 467 } 468 469 pthread_t thread_; // Thread handle for pthread. 470 }; 471 472 473 ThreadHandle::ThreadHandle(Kind kind) { 474 data_ = new PlatformData(kind); 475 } 476 477 478 void ThreadHandle::Initialize(ThreadHandle::Kind kind) { 479 data_->Initialize(kind); 480 } 481 482 483 ThreadHandle::~ThreadHandle() { 484 delete data_; 485 } 486 487 488 bool ThreadHandle::IsSelf() const { 489 return pthread_equal(data_->thread_, pthread_self()); 490 } 491 492 493 bool ThreadHandle::IsValid() const { 494 return data_->thread_ != kNoThread; 495 } 496 497 498 Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) { 499 } 500 501 502 Thread::~Thread() { 503 } 504 505 506 static void* ThreadEntry(void* arg) { 507 Thread* thread = reinterpret_cast<Thread*>(arg); 508 // This is also initialized by the first argument to pthread_create() but we 509 // don't know which thread will run first (the original thread or the new 510 // one) so we initialize it here too. 511 thread->thread_handle_data()->thread_ = pthread_self(); 512 ASSERT(thread->IsValid()); 513 thread->Run(); 514 return NULL; 515 } 516 517 518 void Thread::Start() { 519 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this); 520 ASSERT(IsValid()); 521 } 522 523 524 void Thread::Join() { 525 pthread_join(thread_handle_data()->thread_, NULL); 526 } 527 528 529 Thread::LocalStorageKey Thread::CreateThreadLocalKey() { 530 pthread_key_t key; 531 int result = pthread_key_create(&key, NULL); 532 USE(result); 533 ASSERT(result == 0); 534 return static_cast<LocalStorageKey>(key); 535 } 536 537 538 void Thread::DeleteThreadLocalKey(LocalStorageKey key) { 539 pthread_key_t pthread_key = static_cast<pthread_key_t>(key); 540 int result = pthread_key_delete(pthread_key); 541 USE(result); 542 ASSERT(result == 0); 543 } 544 545 546 void* Thread::GetThreadLocal(LocalStorageKey key) { 547 pthread_key_t pthread_key = static_cast<pthread_key_t>(key); 548 return pthread_getspecific(pthread_key); 549 } 550 551 552 void Thread::SetThreadLocal(LocalStorageKey key, void* value) { 553 pthread_key_t pthread_key = static_cast<pthread_key_t>(key); 554 pthread_setspecific(pthread_key, value); 555 } 556 557 558 void Thread::YieldCPU() { 559 sched_yield(); 560 } 561 562 563 class LinuxMutex : public Mutex { 564 public: 565 566 LinuxMutex() { 567 pthread_mutexattr_t attrs; 568 int result = pthread_mutexattr_init(&attrs); 569 ASSERT(result == 0); 570 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE); 571 ASSERT(result == 0); 572 result = pthread_mutex_init(&mutex_, &attrs); 573 ASSERT(result == 0); 574 } 575 576 virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); } 577 578 virtual int Lock() { 579 int result = pthread_mutex_lock(&mutex_); 580 return result; 581 } 582 583 virtual int Unlock() { 584 int result = pthread_mutex_unlock(&mutex_); 585 return result; 586 } 587 588 private: 589 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms. 590 }; 591 592 593 Mutex* OS::CreateMutex() { 594 return new LinuxMutex(); 595 } 596 597 598 class LinuxSemaphore : public Semaphore { 599 public: 600 explicit LinuxSemaphore(int count) { sem_init(&sem_, 0, count); } 601 virtual ~LinuxSemaphore() { sem_destroy(&sem_); } 602 603 virtual void Wait(); 604 virtual bool Wait(int timeout); 605 virtual void Signal() { sem_post(&sem_); } 606 private: 607 sem_t sem_; 608 }; 609 610 611 void LinuxSemaphore::Wait() { 612 while (true) { 613 int result = sem_wait(&sem_); 614 if (result == 0) return; // Successfully got semaphore. 615 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup. 616 } 617 } 618 619 620 #ifndef TIMEVAL_TO_TIMESPEC 621 #define TIMEVAL_TO_TIMESPEC(tv, ts) do { \ 622 (ts)->tv_sec = (tv)->tv_sec; \ 623 (ts)->tv_nsec = (tv)->tv_usec * 1000; \ 624 } while (false) 625 #endif 626 627 628 bool LinuxSemaphore::Wait(int timeout) { 629 const long kOneSecondMicros = 1000000; // NOLINT 630 631 // Split timeout into second and nanosecond parts. 632 struct timeval delta; 633 delta.tv_usec = timeout % kOneSecondMicros; 634 delta.tv_sec = timeout / kOneSecondMicros; 635 636 struct timeval current_time; 637 // Get the current time. 638 if (gettimeofday(¤t_time, NULL) == -1) { 639 return false; 640 } 641 642 // Calculate time for end of timeout. 643 struct timeval end_time; 644 timeradd(¤t_time, &delta, &end_time); 645 646 struct timespec ts; 647 TIMEVAL_TO_TIMESPEC(&end_time, &ts); 648 // Wait for semaphore signalled or timeout. 649 while (true) { 650 int result = sem_timedwait(&sem_, &ts); 651 if (result == 0) return true; // Successfully got semaphore. 652 if (result > 0) { 653 // For glibc prior to 2.3.4 sem_timedwait returns the error instead of -1. 654 errno = result; 655 result = -1; 656 } 657 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout. 658 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup. 659 } 660 } 661 662 663 Semaphore* OS::CreateSemaphore(int count) { 664 return new LinuxSemaphore(count); 665 } 666 667 668 #ifdef ENABLE_LOGGING_AND_PROFILING 669 670 static Sampler* active_sampler_ = NULL; 671 static pthread_t vm_thread_ = 0; 672 673 674 #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__)) 675 // Android runs a fairly new Linux kernel, so signal info is there, 676 // but the C library doesn't have the structs defined. 677 678 struct sigcontext { 679 uint32_t trap_no; 680 uint32_t error_code; 681 uint32_t oldmask; 682 uint32_t gregs[16]; 683 uint32_t arm_cpsr; 684 uint32_t fault_address; 685 }; 686 typedef uint32_t __sigset_t; 687 typedef struct sigcontext mcontext_t; 688 typedef struct ucontext { 689 uint32_t uc_flags; 690 struct ucontext* uc_link; 691 stack_t uc_stack; 692 mcontext_t uc_mcontext; 693 __sigset_t uc_sigmask; 694 } ucontext_t; 695 enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11}; 696 697 #endif 698 699 700 // A function that determines if a signal handler is called in the context 701 // of a VM thread. 702 // 703 // The problem is that SIGPROF signal can be delivered to an arbitrary thread 704 // (see http://code.google.com/p/google-perftools/issues/detail?id=106#c2) 705 // So, if the signal is being handled in the context of a non-VM thread, 706 // it means that the VM thread is running, and trying to sample its stack can 707 // cause a crash. 708 static inline bool IsVmThread() { 709 // In the case of a single VM thread, this check is enough. 710 if (pthread_equal(pthread_self(), vm_thread_)) return true; 711 // If there are multiple threads that use VM, they must have a thread id 712 // stored in TLS. To verify that the thread is really executing VM, 713 // we check Top's data. Having that ThreadManager::RestoreThread first 714 // restores ThreadLocalTop from TLS, and only then erases the TLS value, 715 // reading Top::thread_id() should not be affected by races. 716 if (ThreadManager::HasId() && !ThreadManager::IsArchived() && 717 ThreadManager::CurrentId() == Top::thread_id()) { 718 return true; 719 } 720 return false; 721 } 722 723 724 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { 725 #ifndef V8_HOST_ARCH_MIPS 726 USE(info); 727 if (signal != SIGPROF) return; 728 if (active_sampler_ == NULL) return; 729 730 TickSample sample; 731 732 // If profiling, we extract the current pc and sp. 733 if (active_sampler_->IsProfiling()) { 734 // Extracting the sample from the context is extremely machine dependent. 735 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); 736 mcontext_t& mcontext = ucontext->uc_mcontext; 737 #if V8_HOST_ARCH_IA32 738 sample.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); 739 sample.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); 740 sample.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]); 741 #elif V8_HOST_ARCH_X64 742 sample.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]); 743 sample.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]); 744 sample.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]); 745 #elif V8_HOST_ARCH_ARM 746 // An undefined macro evaluates to 0, so this applies to Android's Bionic also. 747 #if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) 748 sample.pc = reinterpret_cast<Address>(mcontext.gregs[R15]); 749 sample.sp = reinterpret_cast<Address>(mcontext.gregs[R13]); 750 sample.fp = reinterpret_cast<Address>(mcontext.gregs[R11]); 751 #else 752 sample.pc = reinterpret_cast<Address>(mcontext.arm_pc); 753 sample.sp = reinterpret_cast<Address>(mcontext.arm_sp); 754 sample.fp = reinterpret_cast<Address>(mcontext.arm_fp); 755 #endif 756 #elif V8_HOST_ARCH_MIPS 757 // Implement this on MIPS. 758 UNIMPLEMENTED(); 759 #endif 760 if (IsVmThread()) 761 active_sampler_->SampleStack(&sample); 762 } 763 764 // We always sample the VM state. 765 sample.state = Logger::state(); 766 767 active_sampler_->Tick(&sample); 768 #endif 769 } 770 771 772 class Sampler::PlatformData : public Malloced { 773 public: 774 PlatformData() { 775 signal_handler_installed_ = false; 776 } 777 778 bool signal_handler_installed_; 779 struct sigaction old_signal_handler_; 780 struct itimerval old_timer_value_; 781 }; 782 783 784 Sampler::Sampler(int interval, bool profiling) 785 : interval_(interval), profiling_(profiling), active_(false) { 786 data_ = new PlatformData(); 787 } 788 789 790 Sampler::~Sampler() { 791 delete data_; 792 } 793 794 795 void Sampler::Start() { 796 // There can only be one active sampler at the time on POSIX 797 // platforms. 798 if (active_sampler_ != NULL) return; 799 800 vm_thread_ = pthread_self(); 801 802 // Request profiling signals. 803 struct sigaction sa; 804 sa.sa_sigaction = ProfilerSignalHandler; 805 sigemptyset(&sa.sa_mask); 806 sa.sa_flags = SA_SIGINFO; 807 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; 808 data_->signal_handler_installed_ = true; 809 810 // Set the itimer to generate a tick for each interval. 811 itimerval itimer; 812 itimer.it_interval.tv_sec = interval_ / 1000; 813 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000; 814 itimer.it_value.tv_sec = itimer.it_interval.tv_sec; 815 itimer.it_value.tv_usec = itimer.it_interval.tv_usec; 816 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_); 817 818 // Set this sampler as the active sampler. 819 active_sampler_ = this; 820 active_ = true; 821 } 822 823 824 void Sampler::Stop() { 825 // Restore old signal handler 826 if (data_->signal_handler_installed_) { 827 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL); 828 sigaction(SIGPROF, &data_->old_signal_handler_, 0); 829 data_->signal_handler_installed_ = false; 830 } 831 832 // This sampler is no longer the active sampler. 833 active_sampler_ = NULL; 834 active_ = false; 835 } 836 837 838 #endif // ENABLE_LOGGING_AND_PROFILING 839 840 } } // namespace v8::internal 841