mirror of https://github.com/stella-emu/stella.git
Add threading sanity checks before critical SDL API calls.
This commit is contained in:
parent
b06893d384
commit
8ac66e7929
|
@ -18,10 +18,14 @@
|
|||
#include "OSystem.hxx"
|
||||
#include "EventHandlerSDL2.hxx"
|
||||
|
||||
#include "ThreadDebugging.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem)
|
||||
: EventHandler(osystem)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
|
||||
{
|
||||
|
@ -36,6 +40,8 @@ EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventHandlerSDL2::~EventHandlerSDL2()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
if(SDL_WasInit(SDL_INIT_JOYSTICK))
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||
}
|
||||
|
@ -43,6 +49,8 @@ EventHandlerSDL2::~EventHandlerSDL2()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandlerSDL2::enableTextEvents(bool enable)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
if(enable)
|
||||
SDL_StartTextInput();
|
||||
else
|
||||
|
@ -52,6 +60,8 @@ void EventHandlerSDL2::enableTextEvents(bool enable)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EventHandlerSDL2::pollEvent()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
while(SDL_PollEvent(&myEvent))
|
||||
{
|
||||
switch(myEvent.type)
|
||||
|
@ -210,6 +220,8 @@ void EventHandlerSDL2::pollEvent()
|
|||
EventHandlerSDL2::JoystickSDL2::JoystickSDL2(int idx)
|
||||
: myStick(nullptr)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
myStick = SDL_JoystickOpen(idx);
|
||||
if(myStick)
|
||||
{
|
||||
|
@ -231,6 +243,8 @@ EventHandlerSDL2::JoystickSDL2::JoystickSDL2(int idx)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventHandlerSDL2::JoystickSDL2::~JoystickSDL2()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
if(SDL_WasInit(SDL_INIT_JOYSTICK) && myStick)
|
||||
SDL_JoystickClose(myStick);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "FBSurfaceSDL2.hxx"
|
||||
|
||||
#include "ThreadDebugging.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FBSurfaceSDL2::FBSurfaceSDL2(FrameBufferSDL2& buffer,
|
||||
uInt32 width, uInt32 height, const uInt32* data)
|
||||
|
@ -36,6 +38,8 @@ FBSurfaceSDL2::FBSurfaceSDL2(FrameBufferSDL2& buffer,
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FBSurfaceSDL2::~FBSurfaceSDL2()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
if(mySurface)
|
||||
{
|
||||
SDL_FreeSurface(mySurface);
|
||||
|
@ -48,6 +52,8 @@ FBSurfaceSDL2::~FBSurfaceSDL2()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, ColorId color)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
// Fill the rectangle
|
||||
SDL_Rect tmp;
|
||||
tmp.x = x;
|
||||
|
@ -125,6 +131,8 @@ void FBSurfaceSDL2::translateCoords(Int32& x, Int32& y) const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FBSurfaceSDL2::render()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
if(myIsVisible)
|
||||
{
|
||||
if(myTexAccess == SDL_TEXTUREACCESS_STREAMING)
|
||||
|
@ -139,12 +147,16 @@ bool FBSurfaceSDL2::render()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::invalidate()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
SDL_FillRect(mySurface, nullptr, 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::free()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
if(myTexture)
|
||||
{
|
||||
SDL_DestroyTexture(myTexture);
|
||||
|
@ -155,6 +167,8 @@ void FBSurfaceSDL2::free()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::reload()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
// Re-create texture; the underlying SDL_Surface is fine as-is
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, myInterpolate ? "1" : "0");
|
||||
myTexture = SDL_CreateTexture(myFB.myRenderer, myFB.myPixelFormat->format,
|
||||
|
@ -175,6 +189,8 @@ void FBSurfaceSDL2::reload()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::resize(uInt32 width, uInt32 height)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
// We will only resize when necessary, and not using static textures
|
||||
if((myTexAccess == SDL_TEXTUREACCESS_STATIC) || (mySurface &&
|
||||
int(width) <= mySurface->w && int(height) <= mySurface->h))
|
||||
|
@ -191,6 +207,8 @@ void FBSurfaceSDL2::resize(uInt32 width, uInt32 height)
|
|||
void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height,
|
||||
const uInt32* data)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
// Create a surface in the same format as the parent GL class
|
||||
const SDL_PixelFormat* pf = myFB.myPixelFormat;
|
||||
|
||||
|
|
|
@ -26,12 +26,16 @@
|
|||
#include "FBSurfaceSDL2.hxx"
|
||||
#include "FrameBufferSDL2.hxx"
|
||||
|
||||
#include "ThreadDebugging.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameBufferSDL2::FrameBufferSDL2(OSystem& osystem)
|
||||
: FrameBuffer(osystem),
|
||||
myWindow(nullptr),
|
||||
myRenderer(nullptr)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
// Initialize SDL2 context
|
||||
if(SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
|
||||
{
|
||||
|
@ -52,6 +56,8 @@ FrameBufferSDL2::FrameBufferSDL2(OSystem& osystem)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameBufferSDL2::~FrameBufferSDL2()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
SDL_FreeFormat(myPixelFormat);
|
||||
|
||||
if(myRenderer)
|
||||
|
@ -79,6 +85,8 @@ FrameBufferSDL2::~FrameBufferSDL2()
|
|||
void FrameBufferSDL2::queryHardware(vector<GUI::Size>& displays,
|
||||
VariantList& renderers)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
// First get the maximum windowed desktop resolution
|
||||
SDL_DisplayMode display;
|
||||
int maxDisplays = SDL_GetNumVideoDisplays();
|
||||
|
@ -129,12 +137,16 @@ void FrameBufferSDL2::queryHardware(vector<GUI::Size>& displays,
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int32 FrameBufferSDL2::getCurrentDisplayIndex()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
return SDL_GetWindowDisplayIndex(myWindow);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
// If not initialized by this point, then immediately fail
|
||||
if(SDL_WasInit(SDL_INIT_VIDEO) == 0)
|
||||
return false;
|
||||
|
@ -244,6 +256,8 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL2::setTitle(const string& title)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
myScreenTitle = title;
|
||||
|
||||
if(myWindow)
|
||||
|
@ -253,6 +267,8 @@ void FrameBufferSDL2::setTitle(const string& title)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string FrameBufferSDL2::about() const
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
ostringstream out;
|
||||
out << "Video system: " << SDL_GetCurrentVideoDriver() << endl;
|
||||
SDL_RendererInfo info;
|
||||
|
@ -273,24 +289,32 @@ string FrameBufferSDL2::about() const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL2::invalidate()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
SDL_RenderClear(myRenderer);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL2::showCursor(bool show)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL2::grabMouse(bool grab)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
SDL_SetRelativeMouseMode(grab ? SDL_TRUE : SDL_FALSE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameBufferSDL2::fullScreen() const
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
#ifdef WINDOWED_SUPPORT
|
||||
return SDL_GetWindowFlags(myWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
#else
|
||||
|
@ -301,6 +325,8 @@ bool FrameBufferSDL2::fullScreen() const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL2::renderToScreen()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
// Show all changes made to the renderer
|
||||
SDL_RenderPresent(myRenderer);
|
||||
}
|
||||
|
@ -308,6 +334,8 @@ void FrameBufferSDL2::renderToScreen()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL2::setWindowIcon()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
#ifndef BSPF_MAC_OSX // Currently not needed for OSX
|
||||
#include "stella_icon.hxx" // The Stella icon
|
||||
|
||||
|
@ -329,6 +357,8 @@ unique_ptr<FBSurface>
|
|||
void FrameBufferSDL2::readPixels(uInt8* pixels, uInt32 pitch,
|
||||
const GUI::Rect& rect) const
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
SDL_Rect r;
|
||||
r.x = rect.x(); r.y = rect.y();
|
||||
r.w = rect.width(); r.h = rect.height();
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "audio/SimpleResampler.hxx"
|
||||
#include "audio/LanczosResampler.hxx"
|
||||
|
||||
#include "ThreadDebugging.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings)
|
||||
: Sound(osystem),
|
||||
|
@ -46,6 +48,8 @@ SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings)
|
|||
myUnderrun(false),
|
||||
myAudioSettings(audioSettings)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
myOSystem.logMessage("SoundSDL2::SoundSDL2 started ...", 2);
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
||||
|
@ -69,6 +73,8 @@ SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundSDL2::~SoundSDL2()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
if (!myIsInitializedFlag) return;
|
||||
|
||||
SDL_CloseAudioDevice(myDevice);
|
||||
|
@ -78,6 +84,8 @@ SoundSDL2::~SoundSDL2()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundSDL2::openDevice()
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
SDL_AudioSpec desired;
|
||||
desired.freq = myAudioSettings.sampleRate();
|
||||
desired.format = AUDIO_F32SYS;
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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 <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "ThreadDebugging.hxx"
|
||||
ThreadDebuggingHelper::ThreadDebuggingHelper()
|
||||
: myMainThreadIdConfigured(false)
|
||||
{}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
ThreadDebuggingHelper& ThreadDebuggingHelper::instance()
|
||||
{
|
||||
static ThreadDebuggingHelper instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void ThreadDebuggingHelper::fail(std::string message)
|
||||
{
|
||||
std::cerr << message << std::endl;
|
||||
|
||||
throw std::runtime_error(message);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void ThreadDebuggingHelper::setMainThread()
|
||||
{
|
||||
if (myMainThreadIdConfigured) fail("main thread already configured");
|
||||
|
||||
myMainThreadIdConfigured = true;
|
||||
myMainThreadId = std::this_thread::get_id();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void ThreadDebuggingHelper::assertMainThread()
|
||||
{
|
||||
if (!myMainThreadIdConfigured) fail("main thread not configured");
|
||||
|
||||
if (std::this_thread::get_id() != myMainThreadId) fail("must be called from main thread");
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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 <thread>
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
|
||||
#define SET_MAIN_THREAD ThreadDebuggingHelper::instance().setMainThread();
|
||||
#define ASSERT_MAIN_THREAD ThreadDebuggingHelper::instance().assertMainThread();
|
||||
|
||||
#else
|
||||
|
||||
#define SET_MAIN_THREAD
|
||||
#define ASSERT_MAIN_THREAD
|
||||
|
||||
#endif
|
||||
|
||||
class ThreadDebuggingHelper {
|
||||
|
||||
public:
|
||||
|
||||
void setMainThread();
|
||||
|
||||
void assertMainThread();
|
||||
|
||||
static ThreadDebuggingHelper& instance();
|
||||
|
||||
private:
|
||||
|
||||
void fail(std::string message);
|
||||
|
||||
ThreadDebuggingHelper();
|
||||
|
||||
std::thread::id myMainThreadId;
|
||||
|
||||
bool myMainThreadIdConfigured;
|
||||
|
||||
private:
|
||||
|
||||
ThreadDebuggingHelper(const ThreadDebuggingHelper&) = delete;
|
||||
ThreadDebuggingHelper(ThreadDebuggingHelper&&) = delete;
|
||||
ThreadDebuggingHelper& operator=(const ThreadDebuggingHelper&) = delete;
|
||||
ThreadDebuggingHelper& operator=(ThreadDebuggingHelper&&) = delete;
|
||||
};
|
|
@ -31,6 +31,8 @@
|
|||
#include "PNGLibrary.hxx"
|
||||
#include "System.hxx"
|
||||
|
||||
#include "ThreadDebugging.hxx"
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
#include "Debugger.hxx"
|
||||
#endif
|
||||
|
@ -47,6 +49,8 @@ int stellaMain(int argc, char* argv[])
|
|||
int main(int argc, char* argv[])
|
||||
#endif
|
||||
{
|
||||
SET_MAIN_THREAD;
|
||||
|
||||
std::ios_base::sync_with_stdio(false);
|
||||
|
||||
// Create the parent OSystem object
|
||||
|
|
|
@ -19,7 +19,8 @@ MODULE_OBJS := \
|
|||
src/common/ZipHandler.o \
|
||||
src/common/AudioQueue.o \
|
||||
src/common/AudioSettings.o \
|
||||
src/common/FpsMeter.o
|
||||
src/common/FpsMeter.o \
|
||||
src/common/ThreadDebugging.o
|
||||
|
||||
MODULE_DIRS += \
|
||||
src/common
|
||||
|
|
Loading…
Reference in New Issue