History

Reduce assembly footprint of execute function to allow for specialized tool dispatcher logic Fix locking strategy in scheduler - Release lock prior to notify Change default build optimization to 'for speed' rather than 'full' Add current thread quanta to register and specify size for thread state enum No longer free tool dispatcher after all tools have detached

arr committed 10 years ago

Commit 81423391 parent ed790b411 files · +241 −66Browse files

Showing the changes to src/vm/tool_dispatch.cpp (1 of 11 files). Show all

Unified · Split

src/vm/tool_dispatch.cpp+66−4
@@ -7,6 +7,7 @@ · 6 unmodified lines
7#include <cassert>7#include <cassert>
8#include <vector>8#include <vector>
9#include <debug.h>9#include <debug.h>
10#include <disvm.h>
10#include <vm_tools.h>11#include <vm_tools.h>
11#include <exceptions.h>12#include <exceptions.h>
12#include <utils.h>13#include <utils.h>
@@ -21,7 +22,9 @@ vm_tool_t::~vm_tool_t() · 8 unmodified lines
21}22}
22 23
23vm_tool_dispatch_t::vm_tool_dispatch_t(vm_t &vm)24vm_tool_dispatch_t::vm_tool_dispatch_t(vm_t &vm)
24 : _vm{ vm }25 : _threads_suspended{ false }
26 , _threads_suspended_count{ 0 }
27 , _vm { vm }
25{28{
26 _events.cookie_counter = 1;29 _events.cookie_counter = 1;
27 _breakpoints.cookie_counter = 1;30 _breakpoints.cookie_counter = 1;
@@ -161,6 +164,25 @@ void vm_tool_dispatch_t::on_thread_end(vm_thread_t &t) · 133 unmodified lines
161 _events.fire_event_callbacks(vm_event_t::thread_end, cxt);164 _events.fire_event_callbacks(vm_event_t::thread_end, cxt);
162}165}
163 166
167void vm_tool_dispatch_t::on_thread_broken(vm_thread_t &)
168{
169}
170
171void vm_tool_dispatch_t::block_if_thread_suspended(uint32_t thread_id)
172{
173 if (!_threads_suspended)
174 return;
175
176 std::unique_lock<std::mutex> resume_lock{ _threads_resume_lock };
177
178 _threads_suspended_count++;
179
180 while (_threads_suspended)
181 _threads_resume.wait(resume_lock);
182
183 _threads_suspended_count--;
184}
185
164vm_t& vm_tool_dispatch_t::get_vm_instance() const186vm_t& vm_tool_dispatch_t::get_vm_instance() const
165{187{
166 return _vm;188 return _vm;
@@ -171,7 +193,7 @@ cookie_t vm_tool_dispatch_t::subscribe_event(vm_event_t evt, vm_event_callback_t · 4 unmodified lines
171 if (!cb)193 if (!cb)
172 throw vm_system_exception{ "Invalid callback for event" };194 throw vm_system_exception{ "Invalid callback for event" };
173 195
174 std::lock_guard<std::mutex> lock{ _events.lock };196 std::lock_guard<std::mutex> lock{ _events.event_lock };
175 197
176 const auto cookie_id = _events.cookie_counter++;198 const auto cookie_id = _events.cookie_counter++;
177 199
@@ -190,7 +212,7 @@ cookie_t vm_tool_dispatch_t::subscribe_event(vm_event_t evt, vm_event_callback_t · 12 unmodified lines
190 212
191void vm_tool_dispatch_t::unsubscribe_event(cookie_t cookie_id)213void vm_tool_dispatch_t::unsubscribe_event(cookie_t cookie_id)
192{214{
193 std::lock_guard<std::mutex> lock{ _events.lock };215 std::lock_guard<std::mutex> lock{ _events.event_lock };
194 216
195 auto iter = _events.cookie_to_event.find(cookie_id);217 auto iter = _events.cookie_to_event.find(cookie_id);
196 if (iter == _events.cookie_to_event.cend())218 if (iter == _events.cookie_to_event.cend())
@@ -292,6 +314,46 @@ void vm_tool_dispatch_t::clear_breakpoint(cookie_t cookie_id) · 95 unmodified lines
292 _breakpoints.cookie_to_details.erase(iter_cookie);314 _breakpoints.cookie_to_details.erase(iter_cookie);
293}315}
294 316
317void vm_tool_dispatch_t::suspend_all_threads()
318{
319 std::lock(_threads_suspend_lock, _threads_resume_lock);
320 std::lock_guard<std::mutex> suspend_lock{ _threads_suspend_lock, std::adopt_lock };
321 std::lock_guard<std::mutex> resume_lock{ _threads_resume_lock, std::adopt_lock };
322
323 _threads_suspended = true;
324
325 const auto &sched = _vm.get_scheduler_control();
326
327 auto current = _threads_suspended_count.load();
328 auto max = static_cast<uint32_t>(sched.get_runnable_threads().size());
329
330 // Sleep and check until we determine all threads have been suspended
331 // Minus 1 to exclude the current thread.
332 while (max != 0 && current < (max - 1))
333 {
334 std::this_thread::sleep_for(std::chrono::milliseconds{ 20 });
335 current = _threads_suspended_count.load();
336 max = static_cast<uint32_t>(sched.get_runnable_threads().size());
337 }
338
339 // If the current count is ever equal to the max, then a non vm thread is
340 // inside the tool dispatcher which may be okay, but it indicates a type of
341 // non-invasive debugging that was not originally incorporated into this
342 // dispatcher design.
343 assert(max == 0 || current < max);
344}
345
346void vm_tool_dispatch_t::resume_all_threads()
347{
348 std::lock(_threads_suspend_lock, _threads_resume_lock);
349 std::lock_guard<std::mutex> suspend_lock{ _threads_suspend_lock, std::adopt_lock };
350
351 _threads_suspended = false;
352
353 _threads_resume_lock.unlock();
354 _threads_resume.notify_all();
355}
356
295std::tuple<opcode_t, cookie_t> vm_tool_dispatch_t::get_original_opcode_and_cookie(const vm_registers_t &r)357std::tuple<opcode_t, cookie_t> vm_tool_dispatch_t::get_original_opcode_and_cookie(const vm_registers_t &r)
296{358{
297 const auto module = r.module_ref->module.get();359 const auto module = r.module_ref->module.get();
@@ -320,7 +382,7 @@ void vm_tool_dispatch_t::events_t::fire_event_callbacks(vm_event_t event_type, v · 22 unmodified lines
320 auto event_callbacks = std::vector<vm_event_callback_t>{};382 auto event_callbacks = std::vector<vm_event_callback_t>{};
321 383
322 {384 {
323 std::lock_guard<std::mutex> lock_local{ lock };385 std::lock_guard<std::mutex> lock_local{ event_lock };
324 386
325 auto &event_callbacks_tmp = callbacks[event_type];387 auto &event_callbacks_tmp = callbacks[event_type];
326 for (auto &c : event_callbacks_tmp)388 for (auto &c : event_callbacks_tmp)