|
18 | 18 |
|
19 | 19 | #ifdef _WIN32 |
20 | 20 | #include "GPUDisplayFrontendWindows.h" |
21 | | -#else |
22 | | -#include <pthread.h> |
23 | 21 | #endif |
| 22 | +#include <system_error> |
| 23 | +#include <thread> |
24 | 24 |
|
25 | 25 | #ifdef GPUCA_BUILD_EVENT_DISPLAY_X11 |
26 | 26 | #include "GPUDisplayFrontendX11.h" |
@@ -61,22 +61,31 @@ class GPUDisplayGUIWrapper |
61 | 61 | using namespace o2::gpu; |
62 | 62 |
|
63 | 63 | GPUDisplayFrontend::GPUDisplayFrontend() : mConsole(std::make_unique<GPUDisplayConsole>(std::string(DISPLAY_WINDOW_NAME) + " Console")) {} |
64 | | -GPUDisplayFrontend::~GPUDisplayFrontend() = default; |
| 64 | +GPUDisplayFrontend::~GPUDisplayFrontend() |
| 65 | +{ |
| 66 | + if (mFrontendThread.joinable()) { // Started but not stopped, as the detached thread before |
| 67 | + mFrontendThread.detach(); |
| 68 | + } |
| 69 | +} |
65 | 70 |
|
66 | | -void* GPUDisplayFrontend::FrontendThreadWrapper(void* ptr) |
| 71 | +void GPUDisplayFrontend::FrontendThreadWrapper() |
67 | 72 | { |
68 | | - GPUDisplayFrontend* me = reinterpret_cast<GPUDisplayFrontend*>(ptr); |
69 | 73 | int32_t retVal; |
70 | 74 | try { |
71 | | - retVal = me->FrontendMain(); |
| 75 | + retVal = FrontendMain(); |
72 | 76 | } catch (const std::exception& e) { |
73 | 77 | GPUError("Error in display frontend: %s", e.what()); |
74 | 78 | retVal = -1; |
75 | 79 | } |
76 | | - if (retVal && me->mDisplay->mInitResult == 0) { // Failed before InitDisplay was called, report failure to StartDisplay(), which otherwise waits forever |
77 | | - me->InitDisplay(true); |
| 80 | + if (retVal) { |
| 81 | + std::unique_lock lock(mExitStateMutex); |
| 82 | + if (mDisplay->mInitResult == 0) { // Failed before InitDisplay was called, report failure to StartDisplay(), which otherwise waits forever |
| 83 | + lock.unlock(); |
| 84 | + InitDisplay(true); |
| 85 | + } else { |
| 86 | + mDisplay->mInitResult = -1; // Error after the initialization: StopDisplay does not reset the state for a new start |
| 87 | + } |
78 | 88 | } |
79 | | - return ((void*)(size_t)retVal); |
80 | 89 | } |
81 | 90 |
|
82 | 91 | void GPUDisplayFrontend::waitForFPSLimit() |
@@ -341,35 +350,38 @@ int32_t& GPUDisplayFrontend::drawTextFontSize() |
341 | 350 |
|
342 | 351 | int32_t GPUDisplayFrontend::StartDisplay() |
343 | 352 | { |
344 | | -#ifndef _WIN32 |
345 | | - static pthread_t hThread; |
346 | | - if (pthread_create(&hThread, nullptr, FrontendThreadWrapper, this)) { |
347 | | - GPUError("Coult not Create frontend Thread..."); |
348 | | - return (1); |
349 | | - } |
350 | | -#else |
351 | | - HANDLE hThread; |
352 | | - if ((hThread = CreateThread(nullptr, nullptr, &OpenGLWrapper, this, nullptr, nullptr)) == nullptr) { |
353 | | - GPUError("Coult not Create GL Thread..."); |
| 353 | + try { |
| 354 | + mFrontendThread = std::thread(&GPUDisplayFrontend::FrontendThreadWrapper, this); |
| 355 | + } catch (const std::system_error& e) { |
| 356 | + GPUError("Could not create frontend thread: %s", e.what()); |
354 | 357 | return (1); |
355 | 358 | } |
356 | | -#endif |
357 | | - mDisplay->buildConfig(); |
358 | | - if (mDisplay->cfg().listFrontendOptionHandling) { |
359 | | - listConfig(); |
360 | | - } |
361 | | - return (0); |
| 359 | + std::unique_lock lock(mExitStateMutex); |
| 360 | + mStartDisplayDone = true; |
| 361 | + mInitCV.notify_all(); |
| 362 | + mInitCV.wait(lock, [this] { return mDisplay->mInitResult != 0; }); // Both threads have finished their initialization |
| 363 | + return (mDisplay->mInitResult != 1); |
362 | 364 | } |
363 | 365 |
|
364 | 366 | void GPUDisplayFrontend::StopDisplay() |
365 | 367 | { |
366 | | - std::unique_lock lock(mExitStateMutex); |
367 | | - if (mDisplayRunning) { |
368 | | - mDisplay->mCfgC.mDisplayControl.store(2); |
369 | | - StopDisplayA(); |
370 | | - mDisplay->UnblockDisplay(); |
| 368 | + { |
| 369 | + std::unique_lock lock(mExitStateMutex); |
| 370 | + if (mDisplayRunning) { |
| 371 | + mDisplay->mCfgC.mDisplayControl.store(2); |
| 372 | + StopDisplayA(); |
| 373 | + mDisplay->UnblockDisplay(); |
| 374 | + } |
| 375 | + mDisplayStoppedCV.wait(lock, [this] { return !mDisplayRunning; }); |
| 376 | + } |
| 377 | + if (mFrontendThread.joinable()) { // Also the wrapper has finished (it sets mInitResult = -1 for errors after the initialization), not holding mExitStateMutex, which the wrapper uses |
| 378 | + mFrontendThread.join(); |
| 379 | + } |
| 380 | + std::lock_guard lock(mExitStateMutex); |
| 381 | + if (mDisplay->mInitResult == 1) { // For a new StartDisplay, not after a failed initialization or an error (undefined state) |
| 382 | + mStartDisplayDone = false; |
| 383 | + mDisplay->mInitResult = 0; |
371 | 384 | } |
372 | | - mDisplayStoppedCV.wait(lock, [this] { return !mDisplayRunning; }); |
373 | 385 | } |
374 | 386 |
|
375 | 387 | void GPUDisplayFrontend::StopDisplayA() {} |
0 commit comments