mirror of https://github.com/stella-emu/stella.git
Handle fatal errors on main thread.
This commit is contained in:
parent
8ac66e7929
commit
f08ba16acb
|
@ -15,16 +15,14 @@
|
|||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "ThreadDebugging.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ThreadDebuggingHelper::ThreadDebuggingHelper()
|
||||
: myMainThreadIdConfigured(false)
|
||||
{}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
ThreadDebuggingHelper& ThreadDebuggingHelper::instance()
|
||||
{
|
||||
static ThreadDebuggingHelper instance;
|
||||
|
@ -33,16 +31,14 @@ ThreadDebuggingHelper& ThreadDebuggingHelper::instance()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void ThreadDebuggingHelper::fail(std::string message)
|
||||
void ThreadDebuggingHelper::fail(const string& message)
|
||||
{
|
||||
std::cerr << message << std::endl;
|
||||
cerr << message << endl;
|
||||
|
||||
throw std::runtime_error(message);
|
||||
throw runtime_error(message);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void ThreadDebuggingHelper::setMainThread()
|
||||
{
|
||||
if (myMainThreadIdConfigured) fail("main thread already configured");
|
||||
|
@ -52,7 +48,6 @@ void ThreadDebuggingHelper::setMainThread()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void ThreadDebuggingHelper::assertMainThread()
|
||||
{
|
||||
if (!myMainThreadIdConfigured) fail("main thread not configured");
|
||||
|
|
|
@ -15,8 +15,13 @@
|
|||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef THREADING_DEBUGGER_HXX
|
||||
#define THREADING_DEBUGGER_HXX
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
|
||||
#define SET_MAIN_THREAD ThreadDebuggingHelper::instance().setMainThread();
|
||||
|
@ -41,7 +46,7 @@ class ThreadDebuggingHelper {
|
|||
|
||||
private:
|
||||
|
||||
void fail(std::string message);
|
||||
void fail(const string& message);
|
||||
|
||||
ThreadDebuggingHelper();
|
||||
|
||||
|
@ -56,3 +61,5 @@ class ThreadDebuggingHelper {
|
|||
ThreadDebuggingHelper& operator=(const ThreadDebuggingHelper&) = delete;
|
||||
ThreadDebuggingHelper& operator=(ThreadDebuggingHelper&&) = delete;
|
||||
};
|
||||
|
||||
#endif // THREADING_DEBUGGER_HXX
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "TIA.hxx"
|
||||
#include "Thumbulator.hxx"
|
||||
#include "CartBUS.hxx"
|
||||
#include "exception/FatalEmulationError.hxx"
|
||||
|
||||
// Location of data within the RAM copy of the BUS Driver.
|
||||
#define DSxPTR 0x06D8
|
||||
|
@ -171,11 +172,7 @@ inline void CartridgeBUS::callFunction(uInt8 value)
|
|||
catch(const runtime_error& e) {
|
||||
if(!mySystem->autodetectMode())
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
Debugger::debugger().startWithFatalError(e.what());
|
||||
#else
|
||||
cout << e.what() << endl;
|
||||
#endif
|
||||
FatalEmulationError::raise(e.what());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "Thumbulator.hxx"
|
||||
#include "CartCDF.hxx"
|
||||
#include "TIA.hxx"
|
||||
#include "exception/FatalEmulationError.hxx"
|
||||
|
||||
// Location of data within the RAM copy of the CDF Driver.
|
||||
// Version 0 1
|
||||
|
@ -166,11 +167,7 @@ inline void CartridgeCDF::callFunction(uInt8 value)
|
|||
catch(const runtime_error& e) {
|
||||
if(!mySystem->autodetectMode())
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
Debugger::debugger().startWithFatalError(e.what());
|
||||
#else
|
||||
cout << e.what() << endl;
|
||||
#endif
|
||||
FatalEmulationError::raise(e.what());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "Thumbulator.hxx"
|
||||
#include "CartDPCPlus.hxx"
|
||||
#include "TIA.hxx"
|
||||
#include "exception/FatalEmulationError.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeDPCPlus::CartridgeDPCPlus(const BytePtr& image, uInt32 size,
|
||||
|
@ -191,11 +192,7 @@ inline void CartridgeDPCPlus::callFunction(uInt8 value)
|
|||
catch(const runtime_error& e) {
|
||||
if(!mySystem->autodetectMode())
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
Debugger::debugger().startWithFatalError(e.what());
|
||||
#else
|
||||
cout << e.what() << endl;
|
||||
#endif
|
||||
FatalEmulationError::raise(e.what());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -53,3 +53,9 @@ void DispatchResult::setFatal(uInt64 cycles)
|
|||
|
||||
myStatus = Status::fatal;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DispatchResult::setMessage(const string& message)
|
||||
{
|
||||
myMessage = message;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class DispatchResult
|
|||
|
||||
uInt64 getCycles() const { return myCycles; }
|
||||
|
||||
const string& getMessage() const { assertStatus(Status::debugger); return myMessage; }
|
||||
const string& getMessage() const { assertStatus(Status::debugger, Status::fatal); return myMessage; }
|
||||
|
||||
int getAddress() const { assertStatus(Status::debugger); return myAddress; }
|
||||
|
||||
|
@ -48,10 +48,19 @@ class DispatchResult
|
|||
|
||||
void setFatal(uInt64 cycles);
|
||||
|
||||
void setMessage(const string& message);
|
||||
|
||||
private:
|
||||
|
||||
void assertStatus(Status status) const;
|
||||
|
||||
template<class ...Ts> void assertStatus(Status status, Ts... more) const
|
||||
{
|
||||
if (myStatus == status) return;
|
||||
|
||||
assertStatus(more...);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Status myStatus;
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "System.hxx"
|
||||
#include "M6502.hxx"
|
||||
#include "DispatchResult.hxx"
|
||||
#include "exception/FatalEmulationError.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
M6502::M6502(const Settings& settings)
|
||||
|
@ -306,19 +307,24 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
// Reset the peek/poke address pointers
|
||||
myLastPeekAddress = myLastPokeAddress = myDataAddressForPoke = 0;
|
||||
|
||||
icycles = 0;
|
||||
// Fetch instruction at the program counter
|
||||
IR = peek(PC++, DISASM_CODE); // This address represents a code section
|
||||
try {
|
||||
icycles = 0;
|
||||
|
||||
// Call code to execute the instruction
|
||||
switch(IR)
|
||||
{
|
||||
// 6502 instruction emulation is generated by an M4 macro file
|
||||
#include "M6502.ins"
|
||||
// Fetch instruction at the program counter
|
||||
IR = peek(PC++, DISASM_CODE); // This address represents a code section
|
||||
|
||||
default:
|
||||
// Oops, illegal instruction executed so set fatal error flag
|
||||
myExecutionStatus |= FatalErrorBit;
|
||||
// Call code to execute the instruction
|
||||
switch(IR)
|
||||
{
|
||||
// 6502 instruction emulation is generated by an M4 macro file
|
||||
#include "M6502.ins"
|
||||
|
||||
default:
|
||||
FatalEmulationError::raise("invalid instruction");
|
||||
}
|
||||
} catch (FatalEmulationError& e) {
|
||||
myExecutionStatus |= FatalErrorBit;
|
||||
result.setMessage(e.what());
|
||||
}
|
||||
|
||||
currentCycles = (mySystem->cycles() - previousCycles);
|
||||
|
@ -343,6 +349,15 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
interruptHandler();
|
||||
}
|
||||
|
||||
// See if a fatal error has occured
|
||||
if(myExecutionStatus & FatalErrorBit)
|
||||
{
|
||||
// Yes, so answer that something when wrong. The message has already been set when
|
||||
// the exception was handled.
|
||||
result.setFatal(currentCycles);
|
||||
return;
|
||||
}
|
||||
|
||||
// See if execution has been stopped
|
||||
if(myExecutionStatus & StopExecutionBit)
|
||||
{
|
||||
|
@ -351,18 +366,7 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
return;
|
||||
}
|
||||
|
||||
// See if a fatal error has occured
|
||||
if(myExecutionStatus & FatalErrorBit)
|
||||
{
|
||||
// Yes, so answer that something when wrong
|
||||
result.setFatal(currentCycles + icycles);
|
||||
return;
|
||||
}
|
||||
|
||||
// See if we've executed the specified number of instructions
|
||||
if (currentCycles >= cycles * SYSTEM_CYCLES_PER_CPU)
|
||||
{
|
||||
// Yes, so answer that everything finished fine
|
||||
if (currentCycles >= cycles * SYSTEM_CYCLES_PER_CPU) {
|
||||
result.setOk(currentCycles);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -626,14 +626,34 @@ double OSystem::dispatchEmulation(EmulationWorker& emulationWorker)
|
|||
// Stop the worker and wait until it has finished
|
||||
uInt64 totalCycles = emulationWorker.stop();
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
// Break or trap? -> start debugger
|
||||
if (dispatchResult.getStatus() == DispatchResult::Status::debugger) myDebugger->start(
|
||||
dispatchResult.getMessage(),
|
||||
dispatchResult.getAddress(),
|
||||
dispatchResult.wasReadTrap()
|
||||
);
|
||||
#endif
|
||||
// Handle the dispatch result
|
||||
switch (dispatchResult.getStatus()) {
|
||||
case DispatchResult::Status::ok:
|
||||
break;
|
||||
|
||||
case DispatchResult::Status::debugger:
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
myDebugger->start(
|
||||
dispatchResult.getMessage(),
|
||||
dispatchResult.getAddress(),
|
||||
dispatchResult.wasReadTrap()
|
||||
);
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
case DispatchResult::Status::fatal:
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
myDebugger->startWithFatalError(dispatchResult.getMessage());
|
||||
#else
|
||||
throw runtime_error(dispatchResult.getMessage());
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error("invalid emulation dispatch result");
|
||||
}
|
||||
|
||||
// Handle frying
|
||||
if (dispatchResult.getStatus() == DispatchResult::Status::ok && myEventHandler->frying())
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "FatalEmulationError.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FatalEmulationError::FatalEmulationError(const string& message)
|
||||
: myMessage(message)
|
||||
{}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const char* FatalEmulationError::what() const throw()
|
||||
{
|
||||
return myMessage.c_str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FatalEmulationError::raise(const string& message)
|
||||
{
|
||||
throw FatalEmulationError(message);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef FATAL_EMULATION_ERROR_HXX
|
||||
#define FATAL_EMULATION_ERROR_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
class FatalEmulationError: public std::exception {
|
||||
|
||||
public:
|
||||
|
||||
FatalEmulationError(const string& message);
|
||||
|
||||
virtual const char* what() const throw();
|
||||
|
||||
static void raise(const string& message);
|
||||
|
||||
private:
|
||||
|
||||
const string myMessage;
|
||||
|
||||
};
|
||||
|
||||
#endif // FATAL_EMULATION_ERROR_HXX
|
|
@ -80,7 +80,8 @@ MODULE_OBJS := \
|
|||
src/emucore/Switches.o \
|
||||
src/emucore/System.o \
|
||||
src/emucore/TIASurface.o \
|
||||
src/emucore/Thumbulator.o
|
||||
src/emucore/Thumbulator.o \
|
||||
src/emucore/exception/FatalEmulationError.o
|
||||
|
||||
MODULE_DIRS += \
|
||||
src/emucore
|
||||
|
|
Loading…
Reference in New Issue