Skip to content

Commit

Permalink
platform: do not destroy the Platform instance on exit
Browse files Browse the repository at this point in the history
Otherwise, secondary threads calling TEventQueue::wakeUp() could cause the application to crash on exit.

We do it this way because there is no safe way to destroy the Platform orderly. In theory it could be done with thread_local shared pointers, but this appears to be broken in some compilers (e.g. MINGW).
  • Loading branch information
magiblot committed Oct 22, 2024
1 parent ca00eab commit cafeca0
Show file tree
Hide file tree
Showing 5 changed files with 14 additions and 20 deletions.
4 changes: 1 addition & 3 deletions include/tvision/internal/conctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ class ConsoleCtl

// On Windows, the ConsoleCtl instance is created every time the alternate
// screen buffer is enabled and it is destroyed when restoring the console.
// On Unix, the ConsoleCtl instance is created just once at the beginning
// of the program execution (in static initialization) and destroyed when
// exiting the program.
// On Unix, the ConsoleCtl instance is created just once.

// Creates a global instance if none exists, and returns it.
static ConsoleCtl &getInstance() noexcept;
Expand Down
7 changes: 5 additions & 2 deletions include/tvision/internal/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,10 @@ class Platform

static int (*charWidth)(uint32_t) noexcept;

// Platform is a singleton. It gets created and destroyed by THardwareInfo.
// Platform is a singleton. It gets created by THardwareInfo, but it is
// never destroyed in order to support invocations to 'interruptEventWait'
// from secondary threads.
Platform() noexcept;
~Platform();

// Note: explicit 'this' required by GCC 5.
void setUpConsole() noexcept
Expand Down Expand Up @@ -138,6 +139,8 @@ class Platform
{ console.lock([&] (auto *c) { displayBuf.flushScreen(c->display); }); }
TScreenCell *reloadScreenInfo() noexcept
{ return console.lock([&] (auto *c) { return displayBuf.reloadScreenInfo(c->display); }); }
void freeScreenBuffer() noexcept
{ displayBuf.~DisplayBuffer(); new (&displayBuf) DisplayBuffer; }

bool setClipboardText(TStringView text) noexcept
{ return console.lock([&] (auto *c) { return c->setClipboardText(text); }); }
Expand Down
8 changes: 4 additions & 4 deletions source/platform/hardware.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ static tvision::Platform *platf;
THardwareInfo::THardwareInfo() noexcept
{
using namespace tvision;
static int initPlatform =
(platf = new Platform(), (void) initPlatform, 0);

pendingEvent = 0;
alwaysFlush = getEnv<int>("TVISION_MAX_FPS", 0) < 0;
platf = new Platform();
}

THardwareInfo::~THardwareInfo()
{
delete platf;
platf = nullptr;
}

void THardwareInfo::setCaretSize( ushort size ) noexcept { platf->setCaretSize(size); }
Expand All @@ -48,7 +48,7 @@ void THardwareInfo::screenWrite( ushort x, ushort y, TScreenCell *buf, DWORD len
flushScreen();
}
TScreenCell *THardwareInfo::allocateScreenBuffer() noexcept { return platf->reloadScreenInfo(); }
void THardwareInfo::freeScreenBuffer( TScreenCell * ) noexcept {}
void THardwareInfo::freeScreenBuffer(TScreenCell *) noexcept { platf->freeScreenBuffer(); }
DWORD THardwareInfo::getButtonCount() noexcept { return platf->getButtonCount(); }
void THardwareInfo::cursorOn() noexcept { platf->cursorOn(); }
void THardwareInfo::cursorOff() noexcept { platf->cursorOff(); }
Expand Down
14 changes: 4 additions & 10 deletions source/platform/platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Platform *Platform::instance;

// This is used by TText. It is a global function pointer (instead of an
// instance method) so that it can be used regardless of whether the global
// Platform instance has been created/destroyed or not.
// Platform instance has been created or not.
int (*Platform::charWidth)(uint32_t) noexcept = &Platform::initAndGetCharWidth;

int Platform::initAndGetCharWidth(uint32_t wc) noexcept
Expand Down Expand Up @@ -55,15 +55,6 @@ Platform::Platform() noexcept
initEncodingStuff();
}

Platform::~Platform()
{
restoreConsole();
#ifndef _WIN32
ConsoleCtl::destroyInstance();
#endif
instance = nullptr;
}

void Platform::restoreConsole(ConsoleStrategy *&c) noexcept
{
if (c != &dummyConsole)
Expand All @@ -75,6 +66,9 @@ void Platform::restoreConsole(ConsoleStrategy *&c) noexcept
SignalHandler::disable();
delete c;
c = &dummyConsole;
#ifdef _WIN32
ConsoleCtl::destroyInstance();
#endif
}
}

Expand Down
1 change: 0 additions & 1 deletion source/platform/win32con.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ Win32ConsoleStrategy::~Win32ConsoleStrategy()
delete &input;
SetConsoleCP(cpInput);
SetConsoleOutputCP(cpOutput);
ConsoleCtl::destroyInstance();
}

bool Win32ConsoleStrategy::isAlive() noexcept
Expand Down

0 comments on commit cafeca0

Please sign in to comment.