1 | // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #ifndef RUNTIME_VM_THREAD_INTERRUPTER_H_ |
6 | #define RUNTIME_VM_THREAD_INTERRUPTER_H_ |
7 | |
8 | #include "vm/allocation.h" |
9 | #include "vm/os_thread.h" |
10 | #include "vm/signal_handler.h" |
11 | #include "vm/thread.h" |
12 | |
13 | namespace dart { |
14 | |
15 | struct InterruptedThreadState { |
16 | uintptr_t pc; |
17 | uintptr_t csp; |
18 | uintptr_t dsp; |
19 | uintptr_t fp; |
20 | uintptr_t lr; |
21 | }; |
22 | |
23 | class ThreadInterrupter : public AllStatic { |
24 | public: |
25 | static void Init(); |
26 | |
27 | static void Startup(); |
28 | static void Cleanup(); |
29 | |
30 | // Delay between interrupts. |
31 | static void SetInterruptPeriod(intptr_t period); |
32 | |
33 | // Wake up the thread interrupter thread. |
34 | static void WakeUp(); |
35 | |
36 | // Interrupt a thread. |
37 | static void InterruptThread(OSThread* thread); |
38 | |
39 | class SampleBufferWriterScope : public ValueObject { |
40 | public: |
41 | SampleBufferWriterScope() { |
42 | intptr_t old_value = sample_buffer_lock_.load(std::memory_order_relaxed); |
43 | intptr_t new_value; |
44 | do { |
45 | if (old_value < 0) { |
46 | entered_lock_ = false; |
47 | return; |
48 | } |
49 | new_value = old_value + 1; |
50 | } while (!sample_buffer_lock_.compare_exchange_weak( |
51 | old_value, new_value, std::memory_order_acquire)); |
52 | entered_lock_ = true; |
53 | } |
54 | |
55 | ~SampleBufferWriterScope() { |
56 | if (!entered_lock_) return; |
57 | intptr_t old_value = sample_buffer_lock_.load(std::memory_order_relaxed); |
58 | intptr_t new_value; |
59 | do { |
60 | ASSERT(old_value > 0); |
61 | new_value = old_value - 1; |
62 | } while (!sample_buffer_lock_.compare_exchange_weak( |
63 | old_value, new_value, std::memory_order_release)); |
64 | } |
65 | |
66 | bool CanSample() const { |
67 | return entered_lock_ && |
68 | sample_buffer_waiters_.load(std::memory_order_relaxed) == 0; |
69 | } |
70 | |
71 | private: |
72 | bool entered_lock_; |
73 | DISALLOW_COPY_AND_ASSIGN(SampleBufferWriterScope); |
74 | }; |
75 | |
76 | class SampleBufferReaderScope : public ValueObject { |
77 | public: |
78 | SampleBufferReaderScope() { EnterSampleReader(); } |
79 | ~SampleBufferReaderScope() { ExitSampleReader(); } |
80 | |
81 | private: |
82 | DISALLOW_COPY_AND_ASSIGN(SampleBufferReaderScope); |
83 | }; |
84 | |
85 | private: |
86 | static const intptr_t kMaxThreads = 4096; |
87 | static bool initialized_; |
88 | static bool shutdown_; |
89 | static bool thread_running_; |
90 | static bool woken_up_; |
91 | static ThreadJoinId interrupter_thread_id_; |
92 | static Monitor* monitor_; |
93 | static intptr_t interrupt_period_; |
94 | static intptr_t current_wait_time_; |
95 | |
96 | // Something like a reader-writer lock. Positive values indictate there are |
97 | // outstanding signal handlers that can write to the sample buffer. Negative |
98 | // values indicate there are outstanding sample buffer processors that can |
99 | // read from the sample buffer. A reader will spin-wait to enter the lock. A |
100 | // writer will give up if it fails to enter lock, causing samples to be |
101 | // skipping while we are processing the sample buffer or trying to shut down. |
102 | static std::atomic<intptr_t> sample_buffer_lock_; |
103 | static std::atomic<intptr_t> sample_buffer_waiters_; |
104 | |
105 | static bool IsDebuggerAttached(); |
106 | |
107 | static bool InDeepSleep() { |
108 | return current_wait_time_ == Monitor::kNoTimeout; |
109 | } |
110 | |
111 | static void ThreadMain(uword parameters); |
112 | |
113 | static void InstallSignalHandler(); |
114 | |
115 | static void RemoveSignalHandler(); |
116 | |
117 | static void EnterSampleReader() { |
118 | sample_buffer_waiters_.fetch_add(1, std::memory_order_relaxed); |
119 | |
120 | intptr_t old_value = sample_buffer_lock_.load(std::memory_order_relaxed); |
121 | intptr_t new_value; |
122 | do { |
123 | if (old_value > 0) { |
124 | old_value = sample_buffer_lock_.load(std::memory_order_relaxed); |
125 | continue; // Spin waiting for outstanding SIGPROFs to complete. |
126 | } |
127 | new_value = old_value - 1; |
128 | } while (!sample_buffer_lock_.compare_exchange_weak( |
129 | old_value, new_value, std::memory_order_acquire)); |
130 | } |
131 | |
132 | static void ExitSampleReader() { |
133 | sample_buffer_waiters_.fetch_sub(1, std::memory_order_relaxed); |
134 | |
135 | intptr_t old_value = sample_buffer_lock_.load(std::memory_order_relaxed); |
136 | intptr_t new_value; |
137 | do { |
138 | ASSERT(old_value < 0); |
139 | new_value = old_value + 1; |
140 | } while (!sample_buffer_lock_.compare_exchange_weak( |
141 | old_value, new_value, std::memory_order_release)); |
142 | } |
143 | |
144 | friend class ThreadInterrupterVisitIsolates; |
145 | }; |
146 | |
147 | } // namespace dart |
148 | |
149 | #endif // RUNTIME_VM_THREAD_INTERRUPTER_H_ |
150 | |