From f080656e60000fba0c0e5d9df02046e152c243ea Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Tue, 1 Jan 2019 15:15:09 -0500 Subject: [PATCH] improvements in thread safety and repetition detection in textthread --- GUI/host/host.cpp | 4 ++-- GUI/host/textthread.cpp | 41 ++++++++++++++++++++++------------------- GUI/host/textthread.h | 4 ++-- include/types.h | 4 ++-- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/GUI/host/host.cpp b/GUI/host/host.cpp index 0b42d3e..bc50a70 100644 --- a/GUI/host/host.cpp +++ b/GUI/host/host.cpp @@ -120,7 +120,7 @@ namespace SetWindowsHookExW(WH_GETMESSAGE, [](int statusCode, WPARAM wParam, LPARAM lParam) { if (statusCode == HC_ACTION && wParam == PM_REMOVE && ((MSG*)lParam)->message == WM_CLIPBOARDUPDATE) - if (auto text = Util::GetClipboardText()) Host::GetThread(CLIPBOARD)->PushSentence(text.value()); + if (auto text = Util::GetClipboardText()) Host::GetThread(CLIPBOARD)->AddSentence(text.value()); return CallNextHookEx(NULL, statusCode, wParam, lParam); }, NULL, GetCurrentThreadId()); } @@ -206,6 +206,6 @@ namespace Host void AddConsoleOutput(std::wstring text) { - GetThread(CONSOLE)->PushSentence(text); + GetThread(CONSOLE)->AddSentence(text); } } diff --git a/GUI/host/textthread.cpp b/GUI/host/textthread.cpp index b7d6f81..bd870e5 100644 --- a/GUI/host/textthread.cpp +++ b/GUI/host/textthread.cpp @@ -10,7 +10,7 @@ TextThread::TextThread(ThreadParam tp, HookParam hp, std::optional tp(tp), hp(hp) { - CreateTimerQueueTimer(timer, NULL, [](void* This, BOOLEAN) { ((TextThread*)This)->Flush(); }, this, 25, 25, WT_EXECUTELONGFUNCTION); + CreateTimerQueueTimer(&timer, NULL, [](void* This, BOOLEAN) { ((TextThread*)This)->Flush(); }, this, 10, 10, WT_EXECUTELONGFUNCTION); OnCreate(this); } @@ -19,6 +19,11 @@ TextThread::~TextThread() OnDestroy(this); } +void TextThread::AddSentence(const std::wstring& sentence) +{ + queuedSentences->push_back(sentence); +} + void TextThread::Push(const BYTE* data, int len) { if (len < 0) return; @@ -26,29 +31,27 @@ void TextThread::Push(const BYTE* data, int len) if (hp.type & USING_UNICODE) buffer += std::wstring((wchar_t*)data, len / 2); else if (auto converted = Util::StringToWideString(std::string((char*)data, len), hp.codepage ? hp.codepage : defaultCodepage)) buffer += converted.value(); else Host::AddConsoleOutput(INVALID_CODEPAGE); - if (std::all_of(buffer.begin(), buffer.end(), [&](wchar_t c) { return repeatingChars.count(c) > 0; })) buffer.clear(); lastPushTime = GetTickCount(); -} -void TextThread::PushSentence(std::wstring sentence) -{ - LOCK(bufferMutex); - buffer += sentence; - lastPushTime = 0; + if (std::all_of(buffer.begin(), buffer.end(), [&](wchar_t c) { return repeatingChars.count(c) > 0; })) buffer.clear(); + if (Util::RemoveRepetition(buffer)) // repetition detected, which means the entire sentence has already been received + { + repeatingChars = std::unordered_set(buffer.begin(), buffer.end()); + AddSentence(buffer); + buffer.clear(); + } } void TextThread::Flush() { - std::wstring sentence; - { - LOCK(bufferMutex); - if (buffer.empty()) return; - if (buffer.size() < maxBufferSize && GetTickCount() - lastPushTime < flushDelay) return; - sentence = buffer; - buffer.clear(); + std::vector sentences; + queuedSentences->swap(sentences); + for (auto sentence : sentences) + if (Output(this, sentence)) storage->append(sentence); - if (Util::RemoveRepetition(sentence)) repeatingChars = std::unordered_set(sentence.begin(), sentence.end()); - else repeatingChars.clear(); - } - if (Output(this, sentence)) storage->append(sentence); + LOCK(bufferMutex); + if (buffer.empty()) return; + if (buffer.size() < maxBufferSize && GetTickCount() - lastPushTime < flushDelay) return; + AddSentence(buffer); + buffer.clear(); } diff --git a/GUI/host/textthread.h b/GUI/host/textthread.h index e03b60c..43c5fe2 100644 --- a/GUI/host/textthread.h +++ b/GUI/host/textthread.h @@ -19,9 +19,8 @@ public: TextThread(ThreadParam tp, HookParam hp, std::optional name = {}); ~TextThread(); + void AddSentence(const std::wstring& sentence); void Push(const BYTE* data, int len); - // Flushes ASAP - void PushSentence(std::wstring sentence); ThreadSafe storage; const int64_t handle; @@ -37,5 +36,6 @@ private: std::unordered_set repeatingChars; std::mutex bufferMutex; DWORD lastPushTime; + ThreadSafe> queuedSentences; AutoHandle timer = NULL; // this needs to be last so it's destructed first }; diff --git a/include/types.h b/include/types.h index 01adc92..fed342f 100644 --- a/include/types.h +++ b/include/types.h @@ -9,7 +9,7 @@ template class ThreadSafe { public: - template ThreadSafe(Args ...args) : contents(args...) {} + template ThreadSafe(Args&&... args) : contents(std::forward(args)...) {} auto operator->() { struct @@ -33,7 +33,7 @@ class AutoHandle public: AutoHandle(HANDLE h) : h(h) {} operator HANDLE() { return h.get(); } - operator PHANDLE() { return &h._Myptr(); } + PHANDLE operator&() { return &h._Myptr(); } operator bool() { return h.get() != NULL && h.get() != INVALID_HANDLE_VALUE; } private: