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