Fixed a deadlock caused by the UI thread dropping important messages
This commit is contained in:
parent
a7e4bc8f49
commit
83f7cc27d1
|
@ -14,18 +14,6 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
const DWORD kWmWin32LoopPost = WM_APP + 0x100;
|
|
||||||
const DWORD kWmWin32LoopQuit = WM_APP + 0x101;
|
|
||||||
|
|
||||||
class PostedFn {
|
|
||||||
public:
|
|
||||||
explicit PostedFn(std::function<void()> fn) : fn_(std::move(fn)) {}
|
|
||||||
void Call() { fn_(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::function<void()> fn_;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<Loop> Loop::Create() { return std::make_unique<Win32Loop>(); }
|
std::unique_ptr<Loop> Loop::Create() { return std::make_unique<Win32Loop>(); }
|
||||||
|
|
||||||
Win32Loop::Win32Loop() : thread_id_(0) {
|
Win32Loop::Win32Loop() : thread_id_(0) {
|
||||||
|
@ -64,22 +52,20 @@ Win32Loop::~Win32Loop() {
|
||||||
|
|
||||||
void Win32Loop::ThreadMain() {
|
void Win32Loop::ThreadMain() {
|
||||||
MSG msg;
|
MSG msg;
|
||||||
while (GetMessage(&msg, nullptr, 0, 0)) {
|
while (!should_exit_) {
|
||||||
TranslateMessage(&msg);
|
DWORD result =
|
||||||
DispatchMessage(&msg);
|
MsgWaitForMultipleObjectsEx(0, nullptr, INFINITE, QS_ALLEVENTS, 0);
|
||||||
switch (msg.message) {
|
|
||||||
case kWmWin32LoopPost:
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
if (msg.wParam == reinterpret_cast<WPARAM>(this)) {
|
TranslateMessage(&msg);
|
||||||
auto posted_fn = reinterpret_cast<PostedFn*>(msg.lParam);
|
DispatchMessage(&msg);
|
||||||
posted_fn->Call();
|
}
|
||||||
delete posted_fn;
|
|
||||||
}
|
// Process queued functions.
|
||||||
break;
|
std::lock_guard<std::mutex> lock(posted_functions_mutex_);
|
||||||
case kWmWin32LoopQuit:
|
for (auto it = posted_functions_.begin(); it != posted_functions_.end();) {
|
||||||
if (msg.wParam == reinterpret_cast<WPARAM>(this)) {
|
(*it).Call();
|
||||||
return;
|
it = posted_functions_.erase(it);
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,10 +79,14 @@ bool Win32Loop::is_on_loop_thread() {
|
||||||
|
|
||||||
void Win32Loop::Post(std::function<void()> fn) {
|
void Win32Loop::Post(std::function<void()> fn) {
|
||||||
assert_true(thread_id_ != 0);
|
assert_true(thread_id_ != 0);
|
||||||
if (!PostThreadMessage(
|
{
|
||||||
thread_id_, kWmWin32LoopPost, reinterpret_cast<WPARAM>(this),
|
std::lock_guard<std::mutex> lock(posted_functions_mutex_);
|
||||||
reinterpret_cast<LPARAM>(new PostedFn(std::move(fn))))) {
|
PostedFn posted_fn(fn);
|
||||||
assert_always("Unable to post message to thread queue");
|
posted_functions_.push_back(posted_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!PostThreadMessage(thread_id_, WM_NULL, 0, 0)) {
|
||||||
|
Sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,8 +124,10 @@ void Win32Loop::PostDelayed(std::function<void()> fn, uint64_t delay_millis) {
|
||||||
|
|
||||||
void Win32Loop::Quit() {
|
void Win32Loop::Quit() {
|
||||||
assert_true(thread_id_ != 0);
|
assert_true(thread_id_ != 0);
|
||||||
PostThreadMessage(thread_id_, kWmWin32LoopQuit,
|
should_exit_ = true;
|
||||||
reinterpret_cast<WPARAM>(this), 0);
|
while (!PostThreadMessage(thread_id_, WM_NULL, 0, 0)) {
|
||||||
|
Sleep(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Win32Loop::AwaitQuit() { quit_fence_.Wait(); }
|
void Win32Loop::AwaitQuit() { quit_fence_.Wait(); }
|
||||||
|
|
|
@ -42,17 +42,30 @@ class Win32Loop : public Loop {
|
||||||
std::function<void()> fn;
|
std::function<void()> fn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PostedFn {
|
||||||
|
public:
|
||||||
|
explicit PostedFn(std::function<void()> fn) : fn_(std::move(fn)) {}
|
||||||
|
void Call() { fn_(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void()> fn_;
|
||||||
|
};
|
||||||
|
|
||||||
void ThreadMain();
|
void ThreadMain();
|
||||||
|
|
||||||
static void TimerQueueCallback(void* context, uint8_t);
|
static void TimerQueueCallback(void* context, uint8_t);
|
||||||
|
|
||||||
std::thread thread_;
|
std::thread thread_;
|
||||||
DWORD thread_id_;
|
DWORD thread_id_;
|
||||||
|
bool should_exit_ = false;
|
||||||
xe::threading::Fence quit_fence_;
|
xe::threading::Fence quit_fence_;
|
||||||
|
|
||||||
HANDLE timer_queue_;
|
HANDLE timer_queue_;
|
||||||
std::mutex pending_timers_mutex_;
|
std::mutex pending_timers_mutex_;
|
||||||
std::list<PendingTimer*> pending_timers_;
|
std::list<PendingTimer*> pending_timers_;
|
||||||
|
|
||||||
|
std::mutex posted_functions_mutex_;
|
||||||
|
std::list<PostedFn> posted_functions_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
|
|
Loading…
Reference in New Issue