From 28ab0947c7fbf4224ece0d902be9f946807015d8 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 10 Aug 2016 16:54:06 +0200 Subject: dinput: prevent freeing handle despite static initializer order --- opentrack-dinput/dinput.cpp | 66 ++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 22 deletions(-) (limited to 'opentrack-dinput/dinput.cpp') diff --git a/opentrack-dinput/dinput.cpp b/opentrack-dinput/dinput.cpp index ce80fe0e..06b5e4f2 100644 --- a/opentrack-dinput/dinput.cpp +++ b/opentrack-dinput/dinput.cpp @@ -3,22 +3,11 @@ #include "dinput.hpp" #include -dinput_handle dinput_handle::self; +std::atomic dinput_handle::refcnt; +std::atomic_flag dinput_handle::init_lock = ATOMIC_FLAG_INIT; +dinput_handle::di_t dinput_handle::handle(dinput_handle::make_di()); -dinput_handle::dinput_handle() : handle(init_di()) -{ -} - -dinput_handle::~dinput_handle() -{ - if (handle) - { - handle->Release(); - handle = nullptr; - } -} - -dinput_handle::di_t dinput_handle::init_di() +LPDIRECTINPUT8& dinput_handle::init_di() { HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hr)) @@ -27,13 +16,9 @@ dinput_handle::di_t dinput_handle::init_di() static LPDIRECTINPUT8 di_ = nullptr; if (di_ == nullptr) { - if (SUCCEEDED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&di_, NULL))) - { - return di_; - } - else + if (!SUCCEEDED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&di_, NULL))) { - return di_ = nullptr; + di_ = nullptr; } } return di_; @@ -41,7 +26,44 @@ dinput_handle::di_t dinput_handle::init_di() dinput_handle::di_t dinput_handle::make_di() { - return self.handle; + while (init_lock.test_and_set()) { /* busy loop */ } + + LPDIRECTINPUT8& ret = init_di(); + + init_lock.clear(); + + return di_t(ret); } #endif + +dinput_handle::di_t::di_t(LPDIRECTINPUT8& handle) : handle(handle) +{ + while (init_lock.test_and_set()) { /* busy loop */ } + + refcnt++; + + init_lock.clear(); +} + +void dinput_handle::di_t::free_di() +{ + if (handle) + handle->Release(); + handle = nullptr; +} + +dinput_handle::di_t::~di_t() +{ + while (init_lock.test_and_set()) { /* busy loop */ } + + int refcnt_ = refcnt.fetch_sub(1); + + if (refcnt_ == 1) + { + qDebug() << "exit: deleting di handle"; + free_di(); + } + + init_lock.clear(); +} -- cgit v1.2.3