1 // Copyright 2016 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/libsampler/sampler.h" 6 7 #if V8_OS_POSIX && !V8_OS_CYGWIN 8 9 #define USE_SIGNALS 10 11 #include <errno.h> 12 #include <pthread.h> 13 #include <signal.h> 14 #include <sys/time.h> 15 16 #if !V8_OS_QNX && !V8_OS_AIX 17 #include <sys/syscall.h> // NOLINT 18 #endif 19 20 #if V8_OS_MACOSX 21 #include <mach/mach.h> 22 // OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h> 23 // and is a typedef for struct sigcontext. There is no uc_mcontext. 24 #elif(!V8_OS_ANDROID || defined(__BIONIC_HAVE_UCONTEXT_T)) && !V8_OS_OPENBSD 25 #include <ucontext.h> 26 #endif 27 28 #include <unistd.h> 29 30 // GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'. 31 // Old versions of the C library <signal.h> didn't define the type. 32 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) && \ 33 (defined(__arm__) || defined(__aarch64__)) && \ 34 !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT) 35 #include <asm/sigcontext.h> // NOLINT 36 #endif 37 38 #elif V8_OS_WIN || V8_OS_CYGWIN 39 40 #include "src/base/win32-headers.h" 41 42 #endif 43 44 #include <algorithm> 45 #include <vector> 46 #include <map> 47 48 #include "src/base/atomic-utils.h" 49 #include "src/base/hashmap.h" 50 #include "src/base/platform/platform.h" 51 52 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) 53 54 // Not all versions of Android's C library provide ucontext_t. 55 // Detect this and provide custom but compatible definitions. Note that these 56 // follow the GLibc naming convention to access register values from 57 // mcontext_t. 58 // 59 // See http://code.google.com/p/android/issues/detail?id=34784 60 61 #if defined(__arm__) 62 63 typedef struct sigcontext mcontext_t; 64 65 typedef struct ucontext { 66 uint32_t uc_flags; 67 struct ucontext* uc_link; 68 stack_t uc_stack; 69 mcontext_t uc_mcontext; 70 // Other fields are not used by V8, don't define them here. 71 } ucontext_t; 72 73 #elif defined(__aarch64__) 74 75 typedef struct sigcontext mcontext_t; 76 77 typedef struct ucontext { 78 uint64_t uc_flags; 79 struct ucontext *uc_link; 80 stack_t uc_stack; 81 mcontext_t uc_mcontext; 82 // Other fields are not used by V8, don't define them here. 83 } ucontext_t; 84 85 #elif defined(__mips__) 86 // MIPS version of sigcontext, for Android bionic. 87 typedef struct { 88 uint32_t regmask; 89 uint32_t status; 90 uint64_t pc; 91 uint64_t gregs[32]; 92 uint64_t fpregs[32]; 93 uint32_t acx; 94 uint32_t fpc_csr; 95 uint32_t fpc_eir; 96 uint32_t used_math; 97 uint32_t dsp; 98 uint64_t mdhi; 99 uint64_t mdlo; 100 uint32_t hi1; 101 uint32_t lo1; 102 uint32_t hi2; 103 uint32_t lo2; 104 uint32_t hi3; 105 uint32_t lo3; 106 } mcontext_t; 107 108 typedef struct ucontext { 109 uint32_t uc_flags; 110 struct ucontext* uc_link; 111 stack_t uc_stack; 112 mcontext_t uc_mcontext; 113 // Other fields are not used by V8, don't define them here. 114 } ucontext_t; 115 116 #elif defined(__i386__) 117 // x86 version for Android. 118 typedef struct { 119 uint32_t gregs[19]; 120 void* fpregs; 121 uint32_t oldmask; 122 uint32_t cr2; 123 } mcontext_t; 124 125 typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks 126 typedef struct ucontext { 127 uint32_t uc_flags; 128 struct ucontext* uc_link; 129 stack_t uc_stack; 130 mcontext_t uc_mcontext; 131 // Other fields are not used by V8, don't define them here. 132 } ucontext_t; 133 enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 }; 134 135 #elif defined(__x86_64__) 136 // x64 version for Android. 137 typedef struct { 138 uint64_t gregs[23]; 139 void* fpregs; 140 uint64_t __reserved1[8]; 141 } mcontext_t; 142 143 typedef struct ucontext { 144 uint64_t uc_flags; 145 struct ucontext *uc_link; 146 stack_t uc_stack; 147 mcontext_t uc_mcontext; 148 // Other fields are not used by V8, don't define them here. 149 } ucontext_t; 150 enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 }; 151 #endif 152 153 #endif // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) 154 155 156 namespace v8 { 157 namespace sampler { 158 159 namespace { 160 161 #if defined(USE_SIGNALS) 162 typedef std::vector<Sampler*> SamplerList; 163 typedef SamplerList::iterator SamplerListIterator; 164 typedef base::AtomicValue<bool> AtomicMutex; 165 166 class AtomicGuard { 167 public: 168 explicit AtomicGuard(AtomicMutex* atomic, bool is_blocking = true) 169 : atomic_(atomic), is_success_(false) { 170 do { 171 // Use Acquire_Load to gain mutual exclusion. 172 USE(atomic_->Value()); 173 is_success_ = atomic_->TrySetValue(false, true); 174 } while (is_blocking && !is_success_); 175 } 176 177 bool is_success() const { return is_success_; } 178 179 ~AtomicGuard() { 180 if (!is_success_) return; 181 atomic_->SetValue(false); 182 } 183 184 private: 185 AtomicMutex* const atomic_; 186 bool is_success_; 187 }; 188 189 // Returns key for hash map. 190 void* ThreadKey(pthread_t thread_id) { 191 return reinterpret_cast<void*>(thread_id); 192 } 193 194 // Returns hash value for hash map. 195 uint32_t ThreadHash(pthread_t thread_id) { 196 #if V8_OS_BSD 197 return static_cast<uint32_t>(reinterpret_cast<intptr_t>(thread_id)); 198 #else 199 return static_cast<uint32_t>(thread_id); 200 #endif 201 } 202 203 #endif // USE_SIGNALS 204 205 } // namespace 206 207 #if defined(USE_SIGNALS) 208 209 class Sampler::PlatformData { 210 public: 211 PlatformData() : vm_tid_(pthread_self()) {} 212 pthread_t vm_tid() const { return vm_tid_; } 213 214 private: 215 pthread_t vm_tid_; 216 }; 217 218 class SamplerManager { 219 public: 220 SamplerManager() : sampler_map_() {} 221 222 void AddSampler(Sampler* sampler) { 223 AtomicGuard atomic_guard(&samplers_access_counter_); 224 DCHECK(sampler->IsActive() || !sampler->IsRegistered()); 225 // Add sampler into map if needed. 226 pthread_t thread_id = sampler->platform_data()->vm_tid(); 227 base::HashMap::Entry* entry = 228 sampler_map_.LookupOrInsert(ThreadKey(thread_id), 229 ThreadHash(thread_id)); 230 DCHECK(entry != nullptr); 231 if (entry->value == nullptr) { 232 SamplerList* samplers = new SamplerList(); 233 samplers->push_back(sampler); 234 entry->value = samplers; 235 } else { 236 SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value); 237 bool exists = false; 238 for (SamplerListIterator iter = samplers->begin(); 239 iter != samplers->end(); ++iter) { 240 if (*iter == sampler) { 241 exists = true; 242 break; 243 } 244 } 245 if (!exists) { 246 samplers->push_back(sampler); 247 } 248 } 249 } 250 251 void RemoveSampler(Sampler* sampler) { 252 AtomicGuard atomic_guard(&samplers_access_counter_); 253 DCHECK(sampler->IsActive() || sampler->IsRegistered()); 254 // Remove sampler from map. 255 pthread_t thread_id = sampler->platform_data()->vm_tid(); 256 void* thread_key = ThreadKey(thread_id); 257 uint32_t thread_hash = ThreadHash(thread_id); 258 base::HashMap::Entry* entry = sampler_map_.Lookup(thread_key, thread_hash); 259 DCHECK(entry != nullptr); 260 SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value); 261 for (SamplerListIterator iter = samplers->begin(); iter != samplers->end(); 262 ++iter) { 263 if (*iter == sampler) { 264 samplers->erase(iter); 265 break; 266 } 267 } 268 if (samplers->empty()) { 269 sampler_map_.Remove(thread_key, thread_hash); 270 delete samplers; 271 } 272 } 273 274 #if defined(USE_SIGNALS) 275 void DoSample(const v8::RegisterState& state) { 276 AtomicGuard atomic_guard(&SamplerManager::samplers_access_counter_, false); 277 if (!atomic_guard.is_success()) return; 278 pthread_t thread_id = pthread_self(); 279 base::HashMap::Entry* entry = 280 sampler_map_.Lookup(ThreadKey(thread_id), ThreadHash(thread_id)); 281 if (!entry) return; 282 SamplerList& samplers = *static_cast<SamplerList*>(entry->value); 283 284 for (size_t i = 0; i < samplers.size(); ++i) { 285 Sampler* sampler = samplers[i]; 286 Isolate* isolate = sampler->isolate(); 287 // We require a fully initialized and entered isolate. 288 if (isolate == nullptr || !isolate->IsInUse()) continue; 289 if (v8::Locker::IsActive() && !Locker::IsLocked(isolate)) continue; 290 sampler->SampleStack(state); 291 } 292 } 293 #endif 294 295 static SamplerManager* instance() { return instance_.Pointer(); } 296 297 private: 298 base::HashMap sampler_map_; 299 static AtomicMutex samplers_access_counter_; 300 static base::LazyInstance<SamplerManager>::type instance_; 301 }; 302 303 AtomicMutex SamplerManager::samplers_access_counter_; 304 base::LazyInstance<SamplerManager>::type SamplerManager::instance_ = 305 LAZY_INSTANCE_INITIALIZER; 306 307 #elif V8_OS_WIN || V8_OS_CYGWIN 308 309 // ---------------------------------------------------------------------------- 310 // Win32 profiler support. On Cygwin we use the same sampler implementation as 311 // on Win32. 312 313 class Sampler::PlatformData { 314 public: 315 // Get a handle to the calling thread. This is the thread that we are 316 // going to profile. We need to make a copy of the handle because we are 317 // going to use it in the sampler thread. Using GetThreadHandle() will 318 // not work in this case. We're using OpenThread because DuplicateHandle 319 // for some reason doesn't work in Chrome's sandbox. 320 PlatformData() 321 : profiled_thread_(OpenThread(THREAD_GET_CONTEXT | 322 THREAD_SUSPEND_RESUME | 323 THREAD_QUERY_INFORMATION, 324 false, 325 GetCurrentThreadId())) {} 326 327 ~PlatformData() { 328 if (profiled_thread_ != nullptr) { 329 CloseHandle(profiled_thread_); 330 profiled_thread_ = nullptr; 331 } 332 } 333 334 HANDLE profiled_thread() { return profiled_thread_; } 335 336 private: 337 HANDLE profiled_thread_; 338 }; 339 #endif // USE_SIGNALS 340 341 342 #if defined(USE_SIGNALS) 343 class SignalHandler { 344 public: 345 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } 346 static void TearDown() { 347 delete mutex_; 348 mutex_ = nullptr; 349 } 350 351 static void IncreaseSamplerCount() { 352 base::LockGuard<base::Mutex> lock_guard(mutex_); 353 if (++client_count_ == 1) Install(); 354 } 355 356 static void DecreaseSamplerCount() { 357 base::LockGuard<base::Mutex> lock_guard(mutex_); 358 if (--client_count_ == 0) Restore(); 359 } 360 361 static bool Installed() { 362 base::LockGuard<base::Mutex> lock_guard(mutex_); 363 return signal_handler_installed_; 364 } 365 366 private: 367 static void Install() { 368 struct sigaction sa; 369 sa.sa_sigaction = &HandleProfilerSignal; 370 sigemptyset(&sa.sa_mask); 371 #if V8_OS_QNX 372 sa.sa_flags = SA_SIGINFO; 373 #else 374 sa.sa_flags = SA_RESTART | SA_SIGINFO; 375 #endif 376 signal_handler_installed_ = 377 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); 378 } 379 380 static void Restore() { 381 if (signal_handler_installed_) { 382 sigaction(SIGPROF, &old_signal_handler_, 0); 383 signal_handler_installed_ = false; 384 } 385 } 386 387 static void FillRegisterState(void* context, RegisterState* regs); 388 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); 389 390 // Protects the process wide state below. 391 static base::Mutex* mutex_; 392 static int client_count_; 393 static bool signal_handler_installed_; 394 static struct sigaction old_signal_handler_; 395 }; 396 397 base::Mutex* SignalHandler::mutex_ = nullptr; 398 int SignalHandler::client_count_ = 0; 399 struct sigaction SignalHandler::old_signal_handler_; 400 bool SignalHandler::signal_handler_installed_ = false; 401 402 403 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, 404 void* context) { 405 USE(info); 406 if (signal != SIGPROF) return; 407 v8::RegisterState state; 408 FillRegisterState(context, &state); 409 SamplerManager::instance()->DoSample(state); 410 } 411 412 void SignalHandler::FillRegisterState(void* context, RegisterState* state) { 413 // Extracting the sample from the context is extremely machine dependent. 414 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); 415 #if !(V8_OS_OPENBSD || (V8_OS_LINUX && (V8_HOST_ARCH_PPC || V8_HOST_ARCH_S390))) 416 mcontext_t& mcontext = ucontext->uc_mcontext; 417 #endif 418 #if V8_OS_LINUX 419 #if V8_HOST_ARCH_IA32 420 state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_EIP]); 421 state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_ESP]); 422 state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_EBP]); 423 #elif V8_HOST_ARCH_X64 424 state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]); 425 state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]); 426 state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]); 427 #elif V8_HOST_ARCH_ARM 428 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4) 429 // Old GLibc ARM versions used a gregs[] array to access the register 430 // values from mcontext_t. 431 state->pc = reinterpret_cast<void*>(mcontext.gregs[R15]); 432 state->sp = reinterpret_cast<void*>(mcontext.gregs[R13]); 433 state->fp = reinterpret_cast<void*>(mcontext.gregs[R11]); 434 #else 435 state->pc = reinterpret_cast<void*>(mcontext.arm_pc); 436 state->sp = reinterpret_cast<void*>(mcontext.arm_sp); 437 state->fp = reinterpret_cast<void*>(mcontext.arm_fp); 438 #endif // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4) 439 #elif V8_HOST_ARCH_ARM64 440 state->pc = reinterpret_cast<void*>(mcontext.pc); 441 state->sp = reinterpret_cast<void*>(mcontext.sp); 442 // FP is an alias for x29. 443 state->fp = reinterpret_cast<void*>(mcontext.regs[29]); 444 #elif V8_HOST_ARCH_MIPS 445 state->pc = reinterpret_cast<void*>(mcontext.pc); 446 state->sp = reinterpret_cast<void*>(mcontext.gregs[29]); 447 state->fp = reinterpret_cast<void*>(mcontext.gregs[30]); 448 #elif V8_HOST_ARCH_MIPS64 449 state->pc = reinterpret_cast<void*>(mcontext.pc); 450 state->sp = reinterpret_cast<void*>(mcontext.gregs[29]); 451 state->fp = reinterpret_cast<void*>(mcontext.gregs[30]); 452 #elif V8_HOST_ARCH_PPC 453 state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.regs->nip); 454 state->sp = 455 reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R1]); 456 state->fp = 457 reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R31]); 458 #elif V8_HOST_ARCH_S390 459 #if V8_TARGET_ARCH_32_BIT 460 // 31-bit target will have bit 0 (MSB) of the PSW set to denote addressing 461 // mode. This bit needs to be masked out to resolve actual address. 462 state->pc = 463 reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr & 0x7FFFFFFF); 464 #else 465 state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr); 466 #endif // V8_TARGET_ARCH_32_BIT 467 state->sp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[15]); 468 state->fp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[11]); 469 #endif // V8_HOST_ARCH_* 470 #elif V8_OS_MACOSX 471 #if V8_HOST_ARCH_X64 472 #if __DARWIN_UNIX03 473 state->pc = reinterpret_cast<void*>(mcontext->__ss.__rip); 474 state->sp = reinterpret_cast<void*>(mcontext->__ss.__rsp); 475 state->fp = reinterpret_cast<void*>(mcontext->__ss.__rbp); 476 #else // !__DARWIN_UNIX03 477 state->pc = reinterpret_cast<void*>(mcontext->ss.rip); 478 state->sp = reinterpret_cast<void*>(mcontext->ss.rsp); 479 state->fp = reinterpret_cast<void*>(mcontext->ss.rbp); 480 #endif // __DARWIN_UNIX03 481 #elif V8_HOST_ARCH_IA32 482 #if __DARWIN_UNIX03 483 state->pc = reinterpret_cast<void*>(mcontext->__ss.__eip); 484 state->sp = reinterpret_cast<void*>(mcontext->__ss.__esp); 485 state->fp = reinterpret_cast<void*>(mcontext->__ss.__ebp); 486 #else // !__DARWIN_UNIX03 487 state->pc = reinterpret_cast<void*>(mcontext->ss.eip); 488 state->sp = reinterpret_cast<void*>(mcontext->ss.esp); 489 state->fp = reinterpret_cast<void*>(mcontext->ss.ebp); 490 #endif // __DARWIN_UNIX03 491 #endif // V8_HOST_ARCH_IA32 492 #elif V8_OS_FREEBSD 493 #if V8_HOST_ARCH_IA32 494 state->pc = reinterpret_cast<void*>(mcontext.mc_eip); 495 state->sp = reinterpret_cast<void*>(mcontext.mc_esp); 496 state->fp = reinterpret_cast<void*>(mcontext.mc_ebp); 497 #elif V8_HOST_ARCH_X64 498 state->pc = reinterpret_cast<void*>(mcontext.mc_rip); 499 state->sp = reinterpret_cast<void*>(mcontext.mc_rsp); 500 state->fp = reinterpret_cast<void*>(mcontext.mc_rbp); 501 #elif V8_HOST_ARCH_ARM 502 state->pc = reinterpret_cast<void*>(mcontext.mc_r15); 503 state->sp = reinterpret_cast<void*>(mcontext.mc_r13); 504 state->fp = reinterpret_cast<void*>(mcontext.mc_r11); 505 #endif // V8_HOST_ARCH_* 506 #elif V8_OS_NETBSD 507 #if V8_HOST_ARCH_IA32 508 state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_EIP]); 509 state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_ESP]); 510 state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_EBP]); 511 #elif V8_HOST_ARCH_X64 512 state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_RIP]); 513 state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RSP]); 514 state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RBP]); 515 #endif // V8_HOST_ARCH_* 516 #elif V8_OS_OPENBSD 517 #if V8_HOST_ARCH_IA32 518 state->pc = reinterpret_cast<void*>(ucontext->sc_eip); 519 state->sp = reinterpret_cast<void*>(ucontext->sc_esp); 520 state->fp = reinterpret_cast<void*>(ucontext->sc_ebp); 521 #elif V8_HOST_ARCH_X64 522 state->pc = reinterpret_cast<void*>(ucontext->sc_rip); 523 state->sp = reinterpret_cast<void*>(ucontext->sc_rsp); 524 state->fp = reinterpret_cast<void*>(ucontext->sc_rbp); 525 #endif // V8_HOST_ARCH_* 526 #elif V8_OS_SOLARIS 527 state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_PC]); 528 state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_SP]); 529 state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_FP]); 530 #elif V8_OS_QNX 531 #if V8_HOST_ARCH_IA32 532 state->pc = reinterpret_cast<void*>(mcontext.cpu.eip); 533 state->sp = reinterpret_cast<void*>(mcontext.cpu.esp); 534 state->fp = reinterpret_cast<void*>(mcontext.cpu.ebp); 535 #elif V8_HOST_ARCH_ARM 536 state->pc = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_PC]); 537 state->sp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_SP]); 538 state->fp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_FP]); 539 #endif // V8_HOST_ARCH_* 540 #elif V8_OS_AIX 541 state->pc = reinterpret_cast<void*>(mcontext.jmp_context.iar); 542 state->sp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[1]); 543 state->fp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[31]); 544 #endif // V8_OS_AIX 545 } 546 547 #endif // USE_SIGNALS 548 549 550 void Sampler::SetUp() { 551 #if defined(USE_SIGNALS) 552 SignalHandler::SetUp(); 553 #endif 554 } 555 556 557 void Sampler::TearDown() { 558 #if defined(USE_SIGNALS) 559 SignalHandler::TearDown(); 560 #endif 561 } 562 563 Sampler::Sampler(Isolate* isolate) 564 : is_counting_samples_(false), 565 js_sample_count_(0), 566 external_sample_count_(0), 567 isolate_(isolate), 568 profiling_(false), 569 has_processing_thread_(false), 570 active_(false), 571 registered_(false) { 572 data_ = new PlatformData; 573 } 574 575 Sampler::~Sampler() { 576 DCHECK(!IsActive()); 577 #if defined(USE_SIGNALS) 578 if (IsRegistered()) { 579 SamplerManager::instance()->RemoveSampler(this); 580 } 581 #endif 582 delete data_; 583 } 584 585 void Sampler::Start() { 586 DCHECK(!IsActive()); 587 SetActive(true); 588 #if defined(USE_SIGNALS) 589 SamplerManager::instance()->AddSampler(this); 590 #endif 591 } 592 593 594 void Sampler::Stop() { 595 #if defined(USE_SIGNALS) 596 SamplerManager::instance()->RemoveSampler(this); 597 #endif 598 DCHECK(IsActive()); 599 SetActive(false); 600 SetRegistered(false); 601 } 602 603 604 void Sampler::IncreaseProfilingDepth() { 605 base::NoBarrier_AtomicIncrement(&profiling_, 1); 606 #if defined(USE_SIGNALS) 607 SignalHandler::IncreaseSamplerCount(); 608 #endif 609 } 610 611 612 void Sampler::DecreaseProfilingDepth() { 613 #if defined(USE_SIGNALS) 614 SignalHandler::DecreaseSamplerCount(); 615 #endif 616 base::NoBarrier_AtomicIncrement(&profiling_, -1); 617 } 618 619 620 #if defined(USE_SIGNALS) 621 622 void Sampler::DoSample() { 623 if (!SignalHandler::Installed()) return; 624 if (!IsActive() && !IsRegistered()) { 625 SamplerManager::instance()->AddSampler(this); 626 SetRegistered(true); 627 } 628 pthread_kill(platform_data()->vm_tid(), SIGPROF); 629 } 630 631 #elif V8_OS_WIN || V8_OS_CYGWIN 632 633 void Sampler::DoSample() { 634 HANDLE profiled_thread = platform_data()->profiled_thread(); 635 if (profiled_thread == nullptr) return; 636 637 const DWORD kSuspendFailed = static_cast<DWORD>(-1); 638 if (SuspendThread(profiled_thread) == kSuspendFailed) return; 639 640 // Context used for sampling the register state of the profiled thread. 641 CONTEXT context; 642 memset(&context, 0, sizeof(context)); 643 context.ContextFlags = CONTEXT_FULL; 644 if (GetThreadContext(profiled_thread, &context) != 0) { 645 v8::RegisterState state; 646 #if V8_HOST_ARCH_X64 647 state.pc = reinterpret_cast<void*>(context.Rip); 648 state.sp = reinterpret_cast<void*>(context.Rsp); 649 state.fp = reinterpret_cast<void*>(context.Rbp); 650 #else 651 state.pc = reinterpret_cast<void*>(context.Eip); 652 state.sp = reinterpret_cast<void*>(context.Esp); 653 state.fp = reinterpret_cast<void*>(context.Ebp); 654 #endif 655 SampleStack(state); 656 } 657 ResumeThread(profiled_thread); 658 } 659 660 #endif // USE_SIGNALS 661 662 } // namespace sampler 663 } // namespace v8 664