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
54 const vm_thread_t &thread,54 const vm_thread_t &thread,
55 vm_module_ref_t &entry)55 vm_module_ref_t &entry)
56 : current_thread_state{ vm_thread_state_t::ready }56 : current_thread_state{ vm_thread_state_t::ready }
57 , current_thread_quanta{ 0 }
57 , module_ref{ &entry }58 , module_ref{ &entry }
58 , mp_base{ entry.mp_base }59 , mp_base{ entry.mp_base }
59 , thread{ thread }60 , thread{ thread }
@@ -163,64 +164,89 @@ vm_thread_t::~vm_thread_t() · 103 unmodified lines
163 debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "destroy: vm thread: %d %d\n", _thread_id, _parent_thread_id);164 debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "destroy: vm thread: %d %d\n", _thread_id, _parent_thread_id);
164}165}
165 166
166vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta)167namespace
167{168{
168 _registers.current_thread_state = vm_thread_state_t::running;169 struct execute_with_tool_t
169 assert(_registers.pc != runtime_constants::invalid_program_counter);
170
171 auto execution_duration = uint32_t{ 0 };
172
173 try
174 {170 {
175 for (; execution_duration < quanta; ++execution_duration)171 void begin_exec_loop(vm_registers_t &registers, vm_t &)
176 {172 {
177 if (_registers.stack.peek_frame() == nullptr)173 auto tool_dispatch = registers.tool_dispatch.load();
178 {174 assert(tool_dispatch != nullptr);
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);
181 175
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 };
183 179
184 auto tool_dispatch = _registers.tool_dispatch.load();180 struct execute_normal_t
185 if (tool_dispatch != nullptr)181 {
186 tool_dispatch->on_thread_end(*this);182 void begin_exec_loop(vm_registers_t &, vm_t &) { }
183 };
187 184
188 break;185 template<typename EXEC_DETOUR>
189 }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");
190 194
191 const auto &code_section = _registers.module_ref->code_section;195 const auto &code_section = registers.module_ref->code_section;
192 assert(static_cast<std::size_t>(_registers.pc) < code_section.size());196 assert(static_cast<std::size_t>(registers.pc) < code_section.size());
193 197
194 assert(!_registers.module_ref->is_builtin_module() && "Interpreter thread is unable to execute native instructions");198 assert(!registers.module_ref->is_builtin_module() && "Interpreter thread is unable to execute native instructions");
195 const auto &inst = code_section[_registers.pc].op;199 const auto &inst = code_section[registers.pc].op;
196 const auto opcode = static_cast<std::size_t>(inst.opcode);200 const auto opcode = static_cast<std::size_t>(inst.opcode);
197 if (static_cast<std::size_t>(opcode_t::last_opcode) < opcode)201 if (static_cast<std::size_t>(opcode_t::last_opcode) < opcode)
198 throw vm_system_exception{ "Unknown op-code" };202 throw vm_system_exception{ "Unknown op-code" };
199 203
200 // Instruction is valid, decode and update registers for operation204 // Instruction is valid, decode and update registers for operation
201 decode_address(inst, _registers);205 decode_address(inst, registers);
202 _registers.pc++;206 registers.pc++;
203 vm_exec_table[opcode](_registers, vm);207 vm_exec_table[opcode](registers, vm);
204 208
205 if (_registers.current_thread_state != vm_thread_state_t::running)209 if (registers.current_thread_state != vm_thread_state_t::running)
206 break;210 break;
207 }211 }
208 }212 }
213}
214
215vm_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 }
209 catch (const unhandled_user_exception &uue)229 catch (const unhandled_user_exception &uue)
210 {230 {
211 // [TODO] Store the exception231 // [TODO] Store the exception
212 std::fprintf(stderr, "%s - '%s' in %s at instruction %d\n", uue.what(), uue.exception_id, uue.module_name, uue.program_counter);232 std::fprintf(stderr, "%s - '%s' in %s at instruction %d\n", uue.what(), uue.exception_id, uue.module_name, uue.program_counter);
213 _registers.current_thread_state = vm_thread_state_t::broken;233 _registers.current_thread_state = vm_thread_state_t::broken;
234 if (tool_dispatch != nullptr)
235 tool_dispatch->on_thread_broken(*this);
214 }236 }
215 catch (const index_out_of_range_memory &ioor)237 catch (const index_out_of_range_memory &ioor)
216 {238 {
217 std::fprintf(stderr, "%s - %d [%d,%d]\n", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max);239 std::fprintf(stderr, "%s - %d [%d,%d]\n", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max);
218 _registers.current_thread_state = vm_thread_state_t::broken;240 _registers.current_thread_state = vm_thread_state_t::broken;
241 if (tool_dispatch != nullptr)
242 tool_dispatch->on_thread_broken(*this);
219 }243 }
220 catch (const vm_user_exception &ue)244 catch (const vm_user_exception &ue)
221 {245 {
222 std::fprintf(stderr, "%s\n", ue.what());246 std::fprintf(stderr, "%s\n", ue.what());
223 _registers.current_thread_state = vm_thread_state_t::broken;247 _registers.current_thread_state = vm_thread_state_t::broken;
248 if (tool_dispatch != nullptr)
249 tool_dispatch->on_thread_broken(*this);
224 }250 }
225 251
226 // Log the execution result252 // 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
231 debug::log_level_t::debug,257 debug::log_level_t::debug,
232 "status: vm thread: execute: %d %d %d %d\n",258 "status: vm thread: execute: %d %d %d %d\n",
233 _thread_id,259 _thread_id,
234 execution_duration,260 (quanta - _registers.current_thread_quanta),
235 quanta,261 quanta,
236 _registers.current_thread_state);262 _registers.current_thread_state);
237 }263 }
238 264
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.
240 if (_registers.current_thread_state == vm_thread_state_t::running)266 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 }
242 276
243 return _registers.current_thread_state;277 return _registers.current_thread_state;
244}278}