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 63typedef struct sigcontext mcontext_t; 64 65typedef 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 75typedef struct sigcontext mcontext_t; 76 77typedef 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. 87typedef 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 108typedef 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. 118typedef struct { 119 uint32_t gregs[19]; 120 void* fpregs; 121 uint32_t oldmask; 122 uint32_t cr2; 123} mcontext_t; 124 125typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks 126typedef 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; 133enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 }; 134 135#elif defined(__x86_64__) 136// x64 version for Android. 137typedef struct { 138 uint64_t gregs[23]; 139 void* fpregs; 140 uint64_t __reserved1[8]; 141} mcontext_t; 142 143typedef 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; 150enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 }; 151#endif 152 153#endif // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) 154 155 156namespace v8 { 157namespace sampler { 158 159namespace { 160 161#if defined(USE_SIGNALS) 162typedef std::vector<Sampler*> SamplerList; 163typedef SamplerList::iterator SamplerListIterator; 164typedef base::AtomicValue<bool> AtomicMutex; 165 166class 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. 190void* ThreadKey(pthread_t thread_id) { 191 return reinterpret_cast<void*>(thread_id); 192} 193 194// Returns hash value for hash map. 195uint32_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 209class 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 218class 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 303AtomicMutex SamplerManager::samplers_access_counter_; 304base::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 313class 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) 343class 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 397base::Mutex* SignalHandler::mutex_ = nullptr; 398int SignalHandler::client_count_ = 0; 399struct sigaction SignalHandler::old_signal_handler_; 400bool SignalHandler::signal_handler_installed_ = false; 401 402 403void 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 412void 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 550void Sampler::SetUp() { 551#if defined(USE_SIGNALS) 552 SignalHandler::SetUp(); 553#endif 554} 555 556 557void Sampler::TearDown() { 558#if defined(USE_SIGNALS) 559 SignalHandler::TearDown(); 560#endif 561} 562 563Sampler::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 575Sampler::~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 585void Sampler::Start() { 586 DCHECK(!IsActive()); 587 SetActive(true); 588#if defined(USE_SIGNALS) 589 SamplerManager::instance()->AddSampler(this); 590#endif 591} 592 593 594void 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 604void Sampler::IncreaseProfilingDepth() { 605 base::NoBarrier_AtomicIncrement(&profiling_, 1); 606#if defined(USE_SIGNALS) 607 SignalHandler::IncreaseSamplerCount(); 608#endif 609} 610 611 612void 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 622void 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 633void 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