diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2016-08-10 16:54:06 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2016-08-10 16:54:06 +0200 |
commit | 28ab0947c7fbf4224ece0d902be9f946807015d8 (patch) | |
tree | 5730670e1ae6f58334c05718cc414045d92e5696 | |
parent | cdacaf690a48a3cc1549d9c6e57de2100dc1fc21 (diff) |
dinput: prevent freeing handle despite static initializer order
-rw-r--r-- | opentrack-dinput/dinput.cpp | 66 | ||||
-rw-r--r-- | opentrack-dinput/dinput.hpp | 51 |
2 files changed, 83 insertions, 34 deletions
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 <QDebug> -dinput_handle dinput_handle::self; +std::atomic<int> 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(); +} diff --git a/opentrack-dinput/dinput.hpp b/opentrack-dinput/dinput.hpp index db901887..37a6d723 100644 --- a/opentrack-dinput/dinput.hpp +++ b/opentrack-dinput/dinput.hpp @@ -1,28 +1,55 @@ +/* Copyright (c) 2016, Stanislaw Halik <sthalik@misaki.pl> + + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted, + * provided that the above copyright notice and this permission + * notice appear in all copies. + */ + #pragma once #ifdef _WIN32 +#include "export.hpp" + #ifndef DIRECTINPUT_VERSION # define DIRECTINPUT_VERSION 0x800 #endif -#include "export.hpp" #include <dinput.h> -#include <windows.h> -struct OPENTRACK_DINPUT_EXPORT dinput_handle final +#include <atomic> + +class OPENTRACK_DINPUT_EXPORT dinput_handle final { - using di_t = LPDIRECTINPUT8; +public: + class di_t; + private: - static dinput_handle self; - dinput_handle(); - ~dinput_handle(); - static di_t init_di(); - di_t handle; + static std::atomic<int> refcnt; + static std::atomic_flag init_lock; + static di_t handle; + + static LPDIRECTINPUT8& init_di(); public: - static di_t make_di(); + class di_t final + { + friend class dinput_handle; + + LPDIRECTINPUT8& handle; + + di_t(LPDIRECTINPUT8& handle); + void free_di(); + + public: + LPDIRECTINPUT8 operator->() { return handle; } + operator LPDIRECTINPUT8() { return handle; } + LPDIRECTINPUT8 di() { return handle; } + + ~di_t(); + }; - dinput_handle(const dinput_handle&) = delete; - dinput_handle(dinput_handle&&) = delete; + static di_t make_di(); + dinput_handle() = delete; }; #endif |