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/thread.cpp (1 of 11 files). Show all

Unified · Split

src/vm/thread.cpp+63−29
@@ -54,6 +54,7 @@ vm_registers_t::vm_registers_t( · 53 unmodified lines
5454 const vm_thread_t &thread,
5555 vm_module_ref_t &entry)
5656 : current_thread_state{ vm_thread_state_t::ready }
57+ , current_thread_quanta{ 0 }
5758 , module_ref{ &entry }
5859 , mp_base{ entry.mp_base }
5960 , thread{ thread }
@@ -163,64 +164,89 @@ vm_thread_t::~vm_thread_t() · 103 unmodified lines
163164 debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "destroy: vm thread: %d %d\n", _thread_id, _parent_thread_id);
164165 }
165166
166−vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta)
167+namespace
167168 {
168− _registers.current_thread_state = vm_thread_state_t::running;
169− assert(_registers.pc != runtime_constants::invalid_program_counter);
170−
171− auto execution_duration = uint32_t{ 0 };
172−
173− try
169+ struct execute_with_tool_t
174170 {
175− for (; execution_duration < quanta; ++execution_duration)
171+ void begin_exec_loop(vm_registers_t &registers, vm_t &)
176172 {
177− if (_registers.stack.peek_frame() == nullptr)
178− {
179− if (debug::is_component_tracing_enabled<debug::component_trace_t::thread>())
180− debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "exit: vm thread: stack exhausted: %d\n", _thread_id);
173+ auto tool_dispatch = registers.tool_dispatch.load();
174+ assert(tool_dispatch != nullptr);
181175
182− _registers.current_thread_state = vm_thread_state_t::empty_stack;
176+ tool_dispatch->block_if_thread_suspended(registers.thread.get_thread_id());
177+ }
178+ };
183179
184− auto tool_dispatch = _registers.tool_dispatch.load();
185− if (tool_dispatch != nullptr)
186− tool_dispatch->on_thread_end(*this);
180+ struct execute_normal_t
181+ {
182+ void begin_exec_loop(vm_registers_t &, vm_t &) { }
183+ };
187184
188− break;
189− }
185+ template<typename EXEC_DETOUR>
186+ void execute_impl(vm_registers_t &registers, vm_t &vm)
187+ {
188+ EXEC_DETOUR detour{};
189+ auto &execution_duration = registers.current_thread_quanta;
190+ for (; 0 != execution_duration; --execution_duration)
191+ {
192+ detour.begin_exec_loop(registers, vm);
193+ assert(registers.stack.peek_frame() != nullptr && "Thread state should not be running with empty stack");
190194
191− const auto &code_section = _registers.module_ref->code_section;
192− assert(static_cast<std::size_t>(_registers.pc) < code_section.size());
195+ const auto &code_section = registers.module_ref->code_section;
196+ assert(static_cast<std::size_t>(registers.pc) < code_section.size());
193197
194− assert(!_registers.module_ref->is_builtin_module() && "Interpreter thread is unable to execute native instructions");
195− const auto &inst = code_section[_registers.pc].op;
198+ assert(!registers.module_ref->is_builtin_module() && "Interpreter thread is unable to execute native instructions");
199+ const auto &inst = code_section[registers.pc].op;
196200 const auto opcode = static_cast<std::size_t>(inst.opcode);
197201 if (static_cast<std::size_t>(opcode_t::last_opcode) < opcode)
198202 throw vm_system_exception{ "Unknown op-code" };
199203
200204 // Instruction is valid, decode and update registers for operation
201− decode_address(inst, _registers);
202− _registers.pc++;
203− vm_exec_table[opcode](_registers, vm);
205+ decode_address(inst, registers);
206+ registers.pc++;
207+ vm_exec_table[opcode](registers, vm);
204208
205− if (_registers.current_thread_state != vm_thread_state_t::running)
209+ if (registers.current_thread_state != vm_thread_state_t::running)
206210 break;
207211 }
208212 }
213+}
214+
215+vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta)
216+{
217+ _registers.current_thread_state = vm_thread_state_t::running;
218+ _registers.current_thread_quanta = quanta;
219+ assert(_registers.pc != runtime_constants::invalid_program_counter);
220+ auto tool_dispatch = _registers.tool_dispatch.load();
221+
222+ try
223+ {
224+ if (tool_dispatch == nullptr)
225+ execute_impl<execute_normal_t>(_registers, vm);
226+ else
227+ execute_impl<execute_with_tool_t>(_registers, vm);
228+ }
209229 catch (const unhandled_user_exception &uue)
210230 {
211231 // [TODO] Store the exception
212232 std::fprintf(stderr, "%s - '%s' in %s at instruction %d\n", uue.what(), uue.exception_id, uue.module_name, uue.program_counter);
213233 _registers.current_thread_state = vm_thread_state_t::broken;
234+ if (tool_dispatch != nullptr)
235+ tool_dispatch->on_thread_broken(*this);
214236 }
215237 catch (const index_out_of_range_memory &ioor)
216238 {
217239 std::fprintf(stderr, "%s - %d [%d,%d]\n", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max);
218240 _registers.current_thread_state = vm_thread_state_t::broken;
241+ if (tool_dispatch != nullptr)
242+ tool_dispatch->on_thread_broken(*this);
219243 }
220244 catch (const vm_user_exception &ue)
221245 {
222246 std::fprintf(stderr, "%s\n", ue.what());
223247 _registers.current_thread_state = vm_thread_state_t::broken;
248+ if (tool_dispatch != nullptr)
249+ tool_dispatch->on_thread_broken(*this);
224250 }
225251
226252 // Log the execution result
@@ -231,14 +257,22 @@ vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta) · 4 unmodified lines
231257 debug::log_level_t::debug,
232258 "status: vm thread: execute: %d %d %d %d\n",
233259 _thread_id,
234− execution_duration,
260+ (quanta - _registers.current_thread_quanta),
235261 quanta,
236262 _registers.current_thread_state);
237263 }
238264
239− // If the thread is still in the running state transition it back to ready.
265+ // If the thread is still in the running state transition it back to its entry state.
240266 if (_registers.current_thread_state == vm_thread_state_t::running)
241− _registers.current_thread_state = vm_thread_state_t::ready;
267+ {
268+ _registers.current_thread_state = (tool_dispatch == nullptr) ? vm_thread_state_t::ready : vm_thread_state_t::debug;
269+ }
270+ else if (vm_thread_state_t::exiting == _registers.current_thread_state
271+ || vm_thread_state_t::empty_stack == _registers.current_thread_state)
272+ {
273+ if (tool_dispatch != nullptr)
274+ tool_dispatch->on_thread_end(*this);
275+ }
242276
243277 return _registers.current_thread_state;
244278 }