From 40606d975e73f8e003933c1379e103e654b8d504 Mon Sep 17 00:00:00 2001 From: twanvl Date: Sun, 24 Dec 2006 00:12:06 +0000 Subject: [PATCH] debuged some horrible race conditions & deadlocks git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@160 0fc631ac-6414-0410-93d0-97cfa31319b6 --- src/gfx/resample_image.cpp | 3 +++ src/gui/drop_down_list.cpp | 2 ++ src/gui/thumbnail_thread.cpp | 21 +++++++++------------ src/gui/thumbnail_thread.hpp | 2 +- src/gui/value/choice.cpp | 10 ++++++++-- src/main.cpp | 2 ++ 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/gfx/resample_image.cpp b/src/gfx/resample_image.cpp index 9cc484d5..f3fd421f 100644 --- a/src/gfx/resample_image.cpp +++ b/src/gfx/resample_image.cpp @@ -144,6 +144,8 @@ void resample_and_clip(const Image& img_in, Image& img_out, wxRect rect) { // fill an image with 100% transparent, except for the given rectangle void fill_transparent(Image& img, int dx, int dy, int w, int h) { if (!img.HasAlpha()) img.InitAlpha(); + memset(img.GetAlpha(), 0, img.GetWidth() * img.GetHeight()); + /*/? int iw = img.GetWidth(), ih = img.GetHeight(); Byte* data = img.GetAlpha(); // fill @@ -160,6 +162,7 @@ void fill_transparent(Image& img, int dx, int dy, int w, int h) { for (; y < ih ; ++y) { for (int x = 0 ; x < iw ; ++x) *data++ = 0; } + */ } void resample_preserve_aspect(const Image& img_in, Image& img_out) { diff --git a/src/gui/drop_down_list.cpp b/src/gui/drop_down_list.cpp index 1075bf92..ac775242 100644 --- a/src/gui/drop_down_list.cpp +++ b/src/gui/drop_down_list.cpp @@ -37,8 +37,10 @@ class DropDownHider : public wxEvtHandler { // don't just use ev.Skip(), because this event handler will be removed by hiding, // so there will be no next handler to skip to wxEvtHandler* nh = GetNextHandler(); + wxLogDebug(L"close to %p", nh); list.hide(false); if (nh) nh->ProcessEvent(ev); + wxLogDebug(L"/close to %p", nh); return false; } else { // if (t !=10093 && t !=10098 && t !=10097 && t !=10099 && t !=10004 && t !=10062 diff --git a/src/gui/thumbnail_thread.cpp b/src/gui/thumbnail_thread.cpp index 06e42e15..79e13c36 100644 --- a/src/gui/thumbnail_thread.cpp +++ b/src/gui/thumbnail_thread.cpp @@ -58,7 +58,6 @@ wxThread::ExitCode ThumbnailThreadWorker::Entry() { while (true) { do { Sleep(1); - if (TestDestroy()) return 0; } while (stop); // get a request { @@ -71,9 +70,7 @@ wxThread::ExitCode ThumbnailThreadWorker::Entry() { parent->open_requests.pop_front(); } // perform request - if (TestDestroy()) return 0; Image img = current->generate(); - if (TestDestroy()) return 0; // store in cache if (img.Ok()) { String filename = image_cache_dir() + safe_filename(current->cache_name) + _(".png"); @@ -107,10 +104,6 @@ ThumbnailThread::ThumbnailThread() , worker(nullptr) {} -ThumbnailThread::~ThumbnailThread() { - abortAll(); -} - void ThumbnailThread::request(const ThumbnailRequestP& request) { assert(wxThread::IsMain()); // Is the request in progress? @@ -172,7 +165,7 @@ bool ThumbnailThread::done(void* owner) { void ThumbnailThread::abort(void* owner) { assert(wxThread::IsMain()); mutex.Lock(); - if (worker && worker->current->owner == owner) { + if (worker && worker->current && worker->current->owner == owner) { // a request for this owner is in progress, wait until it is done worker->stop = true; completed.Wait(); @@ -183,8 +176,8 @@ void ThumbnailThread::abort(void* owner) { for (size_t i = 0 ; i < open_requests.size() ; ) { if (open_requests[i]->owner == owner) { // remove - open_requests.erase(open_requests.begin() + i, open_requests.begin() + i + 1); request_names.erase(open_requests[i]); + open_requests.erase(open_requests.begin() + i, open_requests.begin() + i + 1); } else { ++i; } @@ -193,8 +186,8 @@ void ThumbnailThread::abort(void* owner) { for (size_t i = 0 ; i < closed_requests.size() ; ) { if (closed_requests[i].first->owner == owner) { // remove - closed_requests.erase(closed_requests.begin() + i, closed_requests.begin() + i + 1); request_names.erase(closed_requests[i].first); + closed_requests.erase(closed_requests.begin() + i, closed_requests.begin() + i + 1); } else { ++i; } @@ -208,10 +201,14 @@ void ThumbnailThread::abortAll() { open_requests.clear(); closed_requests.clear(); request_names.clear(); - if (worker) { - // a request is in progress, wait until it is done, killing the worker + // end worker + if (worker && worker->current) { completed.Wait(); } else { mutex.Unlock(); } + // There may still be a worker, but if there is, it has no current object, so it is + // in, before or after the stop loop. It can do nothing but end. + // An unfortunate side effect is that we might leak some memory (of the worker object), + // when the thread gets Kill()ed by wx. } diff --git a/src/gui/thumbnail_thread.hpp b/src/gui/thumbnail_thread.hpp index 5a8b4124..ffaf000f 100644 --- a/src/gui/thumbnail_thread.hpp +++ b/src/gui/thumbnail_thread.hpp @@ -48,7 +48,6 @@ class ThumbnailRequest { class ThumbnailThread { public: ThumbnailThread(); - ~ThumbnailThread(); /// Request a thumbnail, it may be store()d immediatly if the thumbnail is cached void request(const ThumbnailRequestP& request); @@ -58,6 +57,7 @@ class ThumbnailThread { /// Abort all thumbnail requests for the given owner void abort(void* owner); /// Abort all computations + /** *must* be called at application exit */ void abortAll(); private: diff --git a/src/gui/value/choice.cpp b/src/gui/value/choice.cpp index f8f94a40..4a549a6c 100644 --- a/src/gui/value/choice.cpp +++ b/src/gui/value/choice.cpp @@ -66,7 +66,9 @@ DropDownChoiceList::DropDownChoiceList(Window* parent, bool is_submenu, ChoiceVa , group(group) , cve(cve) { - icon_size.width = 16; + icon_size.width = 16; + icon_size.height = 16; + item_size.height = max(16., item_size.height); } size_t DropDownChoiceList::itemCount() const { @@ -183,7 +185,9 @@ void DropDownChoiceList::generateThumbnailImages() { void DropDownChoiceList::onIdle(wxIdleEvent& ev) { if (!isRoot()) return; - thumbnail_thread.done(&cve); + if (thumbnail_thread.done(&cve)) { + Refresh(false); + } } BEGIN_EVENT_TABLE(DropDownChoiceList, DropDownList) @@ -201,6 +205,8 @@ ChoiceValueEditor::~ChoiceValueEditor() { } void ChoiceValueEditor::onLeftDown(const RealPoint& pos, wxMouseEvent& ev) { + //HACK TODO REMOVEME + thumbnail_thread.abortAll(); drop_down->onMouseInParent(ev, style().popup_style == POPUP_DROPDOWN_IN_PLACE && !nativeLook()); } void ChoiceValueEditor::onChar(wxKeyEvent& ev) { diff --git a/src/main.cpp b/src/main.cpp index 3ad1e08e..b55b0501 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include // ----------------------------------------------------------------------------- : Main function/class @@ -73,6 +74,7 @@ bool MSE::OnInit() { // ----------------------------------------------------------------------------- : Exit int MSE::OnExit() { + thumbnail_thread.abortAll(); settings.write(); packages.destroy(); return 0;