Merged master into gtk3, manually copied rtgui/threadutils.h over from master

This commit is contained in:
Beep6581
2016-01-31 00:00:28 +01:00
12 changed files with 541 additions and 810 deletions

View File

@@ -99,7 +99,6 @@ option (WITH_BZIP "Build with Bzip2 support" ON)
option (WITH_MYFILE_MMAP "Build using memory mapped file" ON) option (WITH_MYFILE_MMAP "Build using memory mapped file" ON)
option (WITH_LTO "Build with link-time optimizations" OFF) option (WITH_LTO "Build with link-time optimizations" OFF)
option (OPTION_OMP "Build with OpenMP support" ON) option (OPTION_OMP "Build with OpenMP support" ON)
option (PROTECT_VECTORS "Protect critical vectors by custom R/W Mutex, recommanded even if your std::vector is thread safe" ON)
option (STRICT_MUTEX "True (recommended): MyMutex will behave like POSIX Mutex; False: MyMutex will behave like POSIX RecMutex; Note: forced to ON for Debug builds" ON) option (STRICT_MUTEX "True (recommended): MyMutex will behave like POSIX Mutex; False: MyMutex will behave like POSIX RecMutex; Note: forced to ON for Debug builds" ON)
option (TRACE_MYRWMUTEX "Trace RT's custom R/W Mutex (Debug builds only); redirecting std::out to a file is strongly recommended!" OFF) option (TRACE_MYRWMUTEX "Trace RT's custom R/W Mutex (Debug builds only); redirecting std::out to a file is strongly recommended!" OFF)
option (AUTO_GDK_FLUSH "Use gdk_flush on all gdk_thread_leave other than the GUI thread; set it ON if you experience X Server warning/errors" OFF) option (AUTO_GDK_FLUSH "Use gdk_flush on all gdk_thread_leave other than the GUI thread; set it ON if you experience X Server warning/errors" OFF)
@@ -204,13 +203,7 @@ else (STRICT_MUTEX OR UPPER_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
endif (STRICT_MUTEX OR UPPER_CMAKE_BUILD_TYPE STREQUAL "DEBUG") endif (STRICT_MUTEX OR UPPER_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
# MyRWMutex # MyRWMutex
if (PROTECT_VECTORS)
add_definitions (-DPROTECT_VECTORS=1)
else (PROTECT_VECTORS)
add_definitions (-DPROTECT_VECTORS=0)
endif (PROTECT_VECTORS)
if (TRACE_MYRWMUTEX) if (TRACE_MYRWMUTEX)
# Note: it will be set to 0 for Debug builds (rtgui/guiutils.h)
add_definitions (-DTRACE_MYRWMUTEX=1) add_definitions (-DTRACE_MYRWMUTEX=1)
else (TRACE_MYRWMUTEX) else (TRACE_MYRWMUTEX)
add_definitions (-DTRACE_MYRWMUTEX=0) add_definitions (-DTRACE_MYRWMUTEX=0)

View File

@@ -21,7 +21,7 @@ set (BASESOURCEFILES
preferences.cc profilepanel.cc saveasdlg.cc preferences.cc profilepanel.cc saveasdlg.cc
saveformatpanel.cc soundman.cc splash.cc saveformatpanel.cc soundman.cc splash.cc
thumbnail.cc tonecurve.cc toolbar.cc thumbnail.cc tonecurve.cc toolbar.cc
guiutils.cc zoompanel.cc toolpanelcoord.cc guiutils.cc threadutils.cc zoompanel.cc toolpanelcoord.cc
thumbbrowserentrybase.cc batchqueueentry.cc thumbbrowserentrybase.cc batchqueueentry.cc
batchqueue.cc lwbutton.cc lwbuttonset.cc batchqueue.cc lwbutton.cc lwbuttonset.cc
batchqueuebuttonset.cc browserfilter.cc exiffiltersettings.cc batchqueuebuttonset.cc browserfilter.cc exiffiltersettings.cc

View File

@@ -86,9 +86,7 @@ BatchQueue::BatchQueue (FileCatalog* aFileCatalog) : processing(NULL), fileCatal
BatchQueue::~BatchQueue () BatchQueue::~BatchQueue ()
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
// The listener merges parameters with old values, so delete afterwards // The listener merges parameters with old values, so delete afterwards
for (size_t i = 0; i < fd.size(); i++) { for (size_t i = 0; i < fd.size(); i++) {
@@ -100,9 +98,7 @@ BatchQueue::~BatchQueue ()
void BatchQueue::resizeLoadedQueue() void BatchQueue::resizeLoadedQueue()
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
const auto height = getThumbnailHeight (); const auto height = getThumbnailHeight ();
@@ -171,9 +167,7 @@ bool BatchQueue::keyPressed (GdkEventKey* event)
void BatchQueue::addEntries (const std::vector<BatchQueueEntry*>& entries, bool head, bool save) void BatchQueue::addEntries (const std::vector<BatchQueueEntry*>& entries, bool head, bool save)
{ {
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
for (const auto entry : entries) { for (const auto entry : entries) {
@@ -225,9 +219,8 @@ bool BatchQueue::saveBatchQueue ()
return false; return false;
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
if (fd.empty ()) if (fd.empty ())
return true; return true;
@@ -264,9 +257,7 @@ bool BatchQueue::loadBatchQueue ()
if (file.is_open ()) { if (file.is_open ()) {
// Yes, it's better to get the lock for the whole file reading, // Yes, it's better to get the lock for the whole file reading,
// to update the list in one shot without any other concurrent access! // to update the list in one shot without any other concurrent access!
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
std::string row, column; std::string row, column;
std::vector<std::string> values; std::vector<std::string> values;
@@ -398,9 +389,7 @@ int cancelItemUI (void* data)
void BatchQueue::cancelItems (const std::vector<ThumbBrowserEntryBase*>& items) void BatchQueue::cancelItems (const std::vector<ThumbBrowserEntryBase*>& items)
{ {
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
for (const auto item : items) { for (const auto item : items) {
@@ -440,9 +429,8 @@ void BatchQueue::cancelItems (const std::vector<ThumbBrowserEntryBase*>& items)
void BatchQueue::headItems (const std::vector<ThumbBrowserEntryBase*>& items) void BatchQueue::headItems (const std::vector<ThumbBrowserEntryBase*>& items)
{ {
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
for (auto item = items.rbegin(); item != items.rend(); ++item) { for (auto item = items.rbegin(); item != items.rend(); ++item) {
const auto entry = static_cast<BatchQueueEntry*> (*item); const auto entry = static_cast<BatchQueueEntry*> (*item);
@@ -472,9 +460,7 @@ void BatchQueue::headItems (const std::vector<ThumbBrowserEntryBase*>& items)
void BatchQueue::tailItems (const std::vector<ThumbBrowserEntryBase*>& items) void BatchQueue::tailItems (const std::vector<ThumbBrowserEntryBase*>& items)
{ {
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
for (const auto item : items) { for (const auto item : items) {
@@ -502,10 +488,7 @@ void BatchQueue::tailItems (const std::vector<ThumbBrowserEntryBase*>& items)
void BatchQueue::selectAll () void BatchQueue::selectAll ()
{ {
{ {
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
lastClicked = NULL; lastClicked = NULL;
selected.clear (); selected.clear ();
@@ -525,10 +508,7 @@ void BatchQueue::selectAll ()
void BatchQueue::openLastSelectedItemInEditor() void BatchQueue::openLastSelectedItemInEditor()
{ {
{ {
// TODO: Check for Linux
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
if (selected.size() > 0) { if (selected.size() > 0) {
openItemInEditor(selected.back()); openItemInEditor(selected.back());
@@ -550,10 +530,7 @@ void BatchQueue::startProcessing ()
{ {
if (!processing) { if (!processing) {
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
if (!fd.empty()) { if (!fd.empty()) {
BatchQueueEntry* next; BatchQueueEntry* next;
@@ -575,9 +552,7 @@ void BatchQueue::startProcessing ()
processing->selected = false; processing->selected = false;
} }
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
#endif
// remove button set // remove button set
next->removeButtonSet (); next->removeButtonSet ();
@@ -653,10 +628,7 @@ rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImage16* img)
bool remove_button_set = false; bool remove_button_set = false;
{ {
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
delete processing; delete processing;
processing = NULL; processing = NULL;
@@ -700,15 +672,11 @@ rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImage16* img)
// Delete all files in directory \batch when finished, just to be sure to remove zombies // Delete all files in directory \batch when finished, just to be sure to remove zombies
// Not sure that locking is necessary, but it should be safer // Not sure that locking is necessary, but it should be safer
// TODO: Check for Linux
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
if( fd.empty() ) { if( fd.empty() ) {
#if PROTECT_VECTORS
MYREADERLOCK_RELEASE(l); MYREADERLOCK_RELEASE(l);
#endif
std::vector<Glib::ustring> names; std::vector<Glib::ustring> names;
Glib::ustring batchdir = Glib::build_filename(options.rtdir, "batch"); Glib::ustring batchdir = Glib::build_filename(options.rtdir, "batch");
Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path (batchdir); Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path (batchdir);
@@ -950,10 +918,7 @@ void BatchQueue::notifyListener (bool queueEmptied)
NLParams* params = new NLParams; NLParams* params = new NLParams;
params->listener = listener; params->listener = listener;
{ {
// TODO: Check for Linux
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
params->qsize = fd.size(); params->qsize = fd.size();
} }
params->queueEmptied = queueEmptied; params->queueEmptied = queueEmptied;

View File

@@ -83,11 +83,7 @@ public:
bool hasJobs () bool hasJobs ()
{ {
// not sure that this lock is necessary, but it's safer to keep it...
// TODO: Check for Linux
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
return (!fd.empty()); return (!fd.empty());
} }

View File

@@ -244,10 +244,7 @@ void BatchQueueEntry::_updateImage (guint8* img, int w, int h)
{ {
if (preh == h) { if (preh == h) {
#if PROTECT_VECTORS
MYWRITERLOCK(l, lockRW); MYWRITERLOCK(l, lockRW);
#endif
prew = w; prew = w;
assert (preview == NULL); assert (preview == NULL);

View File

@@ -214,7 +214,7 @@ FileBrowser::FileBrowser ()
/*********************** /***********************
* external programs * external programs
* *********************/ * *********************/
#if defined(WIN32) && defined(PROTECT_VECTORS) #if defined(WIN32)
Gtk::manage(miOpenDefaultViewer = new Gtk::MenuItem (M("FILEBROWSER_OPENDEFAULTVIEWER"))); Gtk::manage(miOpenDefaultViewer = new Gtk::MenuItem (M("FILEBROWSER_OPENDEFAULTVIEWER")));
#else #else
miOpenDefaultViewer = NULL; miOpenDefaultViewer = NULL;
@@ -467,9 +467,7 @@ void FileBrowser::rightClicked (ThumbBrowserEntryBase* entry)
{ {
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
trash->set_sensitive (false); trash->set_sensitive (false);
untrash->set_sensitive (false); untrash->set_sensitive (false);
@@ -606,9 +604,7 @@ void FileBrowser::addEntry_ (FileBrowserEntry* entry)
// find place in abc order // find place in abc order
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
std::vector<ThumbBrowserEntryBase*>::iterator i = fd.begin(); std::vector<ThumbBrowserEntryBase*>::iterator i = fd.begin();
@@ -628,9 +624,7 @@ void FileBrowser::addEntry_ (FileBrowserEntry* entry)
FileBrowserEntry* FileBrowser::delEntry (const Glib::ustring& fname) FileBrowserEntry* FileBrowser::delEntry (const Glib::ustring& fname)
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
for (std::vector<ThumbBrowserEntryBase*>::iterator i = fd.begin(); i != fd.end(); i++) for (std::vector<ThumbBrowserEntryBase*>::iterator i = fd.begin(); i != fd.end(); i++)
if ((*i)->filename == fname) { if ((*i)->filename == fname) {
@@ -639,9 +633,7 @@ FileBrowserEntry* FileBrowser::delEntry (const Glib::ustring& fname)
fd.erase (i); fd.erase (i);
std::vector<ThumbBrowserEntryBase*>::iterator j = std::find (selected.begin(), selected.end(), entry); std::vector<ThumbBrowserEntryBase*>::iterator j = std::find (selected.begin(), selected.end(), entry);
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
#endif
if (j != selected.end()) { if (j != selected.end()) {
if (checkFilter (*j)) { if (checkFilter (*j)) {
@@ -678,21 +670,15 @@ void FileBrowser::close ()
fbih->pending = 0; fbih->pending = 0;
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
selected.clear (); selected.clear ();
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); // notifySelectionListener will need read access! MYWRITERLOCK_RELEASE(l); // notifySelectionListener will need read access!
#endif
notifySelectionListener (); notifySelectionListener ();
#if PROTECT_VECTORS
MYWRITERLOCK_ACQUIRE(l); MYWRITERLOCK_ACQUIRE(l);
#endif
// The listener merges parameters with old values, so delete afterwards // The listener merges parameters with old values, so delete afterwards
for (size_t i = 0; i < fd.size(); i++) { for (size_t i = 0; i < fd.size(); i++) {
@@ -724,9 +710,7 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m)
std::vector<FileBrowserEntry*> mselected; std::vector<FileBrowserEntry*> mselected;
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
for (size_t i = 0; i < selected.size(); i++) { for (size_t i = 0; i < selected.size(); i++) {
mselected.push_back (static_cast<FileBrowserEntry*>(selected[i])); mselected.push_back (static_cast<FileBrowserEntry*>(selected[i]));
@@ -796,9 +780,7 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m)
} else if (m == selall) { } else if (m == selall) {
lastClicked = NULL; lastClicked = NULL;
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
selected.clear (); selected.clear ();
@@ -1018,9 +1000,7 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m)
void FileBrowser::copyProfile () void FileBrowser::copyProfile ()
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
if (selected.size() == 1) { if (selected.size() == 1) {
clipboard.setProcParams ((static_cast<FileBrowserEntry*>(selected[0]))->thumbnail->getProcParams()); clipboard.setProcParams ((static_cast<FileBrowserEntry*>(selected[0]))->thumbnail->getProcParams());
@@ -1033,9 +1013,7 @@ void FileBrowser::pasteProfile ()
if (clipboard.hasProcParams()) { if (clipboard.hasProcParams()) {
std::vector<FileBrowserEntry*> mselected; std::vector<FileBrowserEntry*> mselected;
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
for (unsigned int i = 0; i < selected.size(); i++) { for (unsigned int i = 0; i < selected.size(); i++) {
mselected.push_back (static_cast<FileBrowserEntry*>(selected[i])); mselected.push_back (static_cast<FileBrowserEntry*>(selected[i]));
@@ -1075,9 +1053,7 @@ void FileBrowser::partPasteProfile ()
std::vector<FileBrowserEntry*> mselected; std::vector<FileBrowserEntry*> mselected;
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
for (unsigned int i = 0; i < selected.size(); i++) { for (unsigned int i = 0; i < selected.size(); i++) {
mselected.push_back (static_cast<FileBrowserEntry*>(selected[i])); mselected.push_back (static_cast<FileBrowserEntry*>(selected[i]));
@@ -1129,9 +1105,7 @@ void FileBrowser::openDefaultViewer (int destination)
bool success = true; bool success = true;
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
if (selected.size() == 1) { if (selected.size() == 1) {
success = (static_cast<FileBrowserEntry*>(selected[0]))->thumbnail->openDefaultViewer(destination); success = (static_cast<FileBrowserEntry*>(selected[0]))->thumbnail->openDefaultViewer(destination);
@@ -1365,10 +1339,7 @@ int FileBrowser::getThumbnailHeight ()
void FileBrowser::applyMenuItemActivated (ProfileStoreLabel *label) void FileBrowser::applyMenuItemActivated (ProfileStoreLabel *label)
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
const rtengine::procparams::PartialProfile* partProfile = profileStore.getProfile (label->entry); const rtengine::procparams::PartialProfile* partProfile = profileStore.getProfile (label->entry);
@@ -1393,9 +1364,7 @@ void FileBrowser::applyPartialMenuItemActivated (ProfileStoreLabel *label)
{ {
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
if (!tbl || selected.empty()) { if (!tbl || selected.empty()) {
return; return;
@@ -1411,9 +1380,7 @@ void FileBrowser::applyPartialMenuItemActivated (ProfileStoreLabel *label)
if (partialPasteDlg.run() == Gtk::RESPONSE_OK) { if (partialPasteDlg.run() == Gtk::RESPONSE_OK) {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
if (bppcl) { if (bppcl) {
bppcl->beginBatchPParamsChange(selected.size()); bppcl->beginBatchPParamsChange(selected.size());
@@ -1450,9 +1417,7 @@ void FileBrowser::applyFilter (const BrowserFilter& filter)
bool selchanged = false; bool selchanged = false;
numFiltered = 0; numFiltered = 0;
{ {
#if PROTECT_VECTORS MYWRITERLOCK(l, entryRW);
MYWRITERLOCK(l, entryRW); // Don't make this a writer lock! HOMBRE: Why? 'selected' is modified here
#endif
if (filter.showOriginal) { if (filter.showOriginal) {
findOriginalEntries(fd); findOriginalEntries(fd);
@@ -1703,9 +1668,7 @@ void FileBrowser::requestRanking(int rank)
{ {
std::vector<FileBrowserEntry*> mselected; std::vector<FileBrowserEntry*> mselected;
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
for (size_t i = 0; i < selected.size(); i++) { for (size_t i = 0; i < selected.size(); i++) {
mselected.push_back (static_cast<FileBrowserEntry*>(selected[i])); mselected.push_back (static_cast<FileBrowserEntry*>(selected[i]));
@@ -1719,9 +1682,7 @@ void FileBrowser::requestColorLabel(int colorlabel)
{ {
std::vector<FileBrowserEntry*> mselected; std::vector<FileBrowserEntry*> mselected;
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
for (size_t i = 0; i < selected.size(); i++) { for (size_t i = 0; i < selected.size(); i++) {
mselected.push_back (static_cast<FileBrowserEntry*>(selected[i])); mselected.push_back (static_cast<FileBrowserEntry*>(selected[i]));
@@ -1761,9 +1722,7 @@ void FileBrowser::buttonPressed (LWButton* button, int actionCode, void* actionD
void FileBrowser::openNextImage () void FileBrowser::openNextImage ()
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
if (!fd.empty() && selected.size() > 0 && !options.tabbedUI) { if (!fd.empty() && selected.size() > 0 && !options.tabbedUI) {
@@ -1785,16 +1744,12 @@ void FileBrowser::openNextImage ()
selected.push_back (fd[k]); selected.push_back (fd[k]);
//queue_draw (); //queue_draw ();
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
#endif
// this will require a read access // this will require a read access
notifySelectionListener (); notifySelectionListener ();
#if PROTECT_VECTORS
MYWRITERLOCK_ACQUIRE(l); MYWRITERLOCK_ACQUIRE(l);
#endif
// scroll to the selected position // scroll to the selected position
double h1, v1; double h1, v1;
@@ -1806,9 +1761,7 @@ void FileBrowser::openNextImage ()
Thumbnail* thumb = (static_cast<FileBrowserEntry*>(fd[k]))->thumbnail; Thumbnail* thumb = (static_cast<FileBrowserEntry*>(fd[k]))->thumbnail;
int minWidth = get_width() - fd[k]->getMinimalWidth(); int minWidth = get_width() - fd[k]->getMinimalWidth();
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
#endif
// scroll only when selected[0] is outside of the displayed bounds // scroll only when selected[0] is outside of the displayed bounds
if (h2 + minWidth - h1 > get_width()) { if (h2 + minWidth - h1 > get_width()) {
@@ -1834,9 +1787,7 @@ void FileBrowser::openNextImage ()
void FileBrowser::openPrevImage () void FileBrowser::openPrevImage ()
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
if (!fd.empty() && selected.size() > 0 && !options.tabbedUI) { if (!fd.empty() && selected.size() > 0 && !options.tabbedUI) {
@@ -1858,16 +1809,12 @@ void FileBrowser::openPrevImage ()
selected.push_back (fd[k]); selected.push_back (fd[k]);
//queue_draw (); //queue_draw ();
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
#endif
// this will require a read access // this will require a read access
notifySelectionListener (); notifySelectionListener ();
#if PROTECT_VECTORS
MYWRITERLOCK_ACQUIRE(l); MYWRITERLOCK_ACQUIRE(l);
#endif
// scroll to the selected position // scroll to the selected position
double h1, v1; double h1, v1;
@@ -1879,9 +1826,7 @@ void FileBrowser::openPrevImage ()
Thumbnail* thumb = (static_cast<FileBrowserEntry*>(fd[k]))->thumbnail; Thumbnail* thumb = (static_cast<FileBrowserEntry*>(fd[k]))->thumbnail;
int minWidth = get_width() - fd[k]->getMinimalWidth(); int minWidth = get_width() - fd[k]->getMinimalWidth();
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
#endif
// scroll only when selected[0] is outside of the displayed bounds // scroll only when selected[0] is outside of the displayed bounds
if (h2 + minWidth - h1 > get_width()) { if (h2 + minWidth - h1 > get_width()) {
@@ -1910,10 +1855,7 @@ void FileBrowser::selectImage (Glib::ustring fname)
{ {
// need to clear the filter in filecatalog // need to clear the filter in filecatalog
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
if (!fd.empty() && !options.tabbedUI) { if (!fd.empty() && !options.tabbedUI) {
for (size_t i = 0; i < fd.size(); i++) { for (size_t i = 0; i < fd.size(); i++) {
@@ -1932,24 +1874,18 @@ void FileBrowser::selectImage (Glib::ustring fname)
selected.push_back (fd[i]); selected.push_back (fd[i]);
queue_draw (); queue_draw ();
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
#endif
// this will require a read access // this will require a read access
notifySelectionListener (); notifySelectionListener ();
#if PROTECT_VECTORS
MYWRITERLOCK_ACQUIRE(l); MYWRITERLOCK_ACQUIRE(l);
#endif
// scroll to the selected position // scroll to the selected position
double h = selected[0]->getStartX(); double h = selected[0]->getStartX();
double v = selected[0]->getStartY(); double v = selected[0]->getStartY();
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
#endif
setScrollPosition(h, v); setScrollPosition(h, v);
@@ -2000,9 +1936,7 @@ void FileBrowser::notifySelectionListener ()
{ {
if (tbl) { if (tbl) {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
std::vector<Thumbnail*> thm; std::vector<Thumbnail*> thm;

View File

@@ -238,10 +238,7 @@ void FileBrowserEntry::updateImage (rtengine::IImage8* img, double scale, rtengi
void FileBrowserEntry::_updateImage (rtengine::IImage8* img, double s, rtengine::procparams::CropParams cropParams) void FileBrowserEntry::_updateImage (rtengine::IImage8* img, double s, rtengine::procparams::CropParams cropParams)
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, lockRW); MYWRITERLOCK(l, lockRW);
#endif
redrawRequests--; redrawRequests--;
scale = s; scale = s;

View File

@@ -32,11 +32,6 @@
using namespace std; using namespace std;
#if TRACE_MYRWMUTEX==1 && !defined NDEBUG
unsigned int MyReaderLock::readerLockCounter = 0;
unsigned int MyWriterLock::writerLockCounter = 0;
#endif
Glib::RefPtr<Gdk::Pixbuf> MyExpander::inconsistentPBuf; Glib::RefPtr<Gdk::Pixbuf> MyExpander::inconsistentPBuf;
Glib::RefPtr<Gdk::Pixbuf> MyExpander::enabledPBuf; Glib::RefPtr<Gdk::Pixbuf> MyExpander::enabledPBuf;
Glib::RefPtr<Gdk::Pixbuf> MyExpander::disabledPBuf; Glib::RefPtr<Gdk::Pixbuf> MyExpander::disabledPBuf;

292
rtgui/threadutils.cc Normal file
View File

@@ -0,0 +1,292 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2016 Adam Reichold <adam.reichold@t-online.de>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include "threadutils.h"
#include <csignal>
#include <iostream>
#ifdef WIN32
#include <windows.h>
#endif
#if STRICT_MUTEX && !NDEBUG
void MyMutex::checkLock ()
{
if (locked) {
std::cerr << "MyMutex already locked!" << std::endl;
#ifdef WIN32
DebugBreak ();
#else
raise (SIGTRAP);
#endif
}
locked = true;
}
void MyMutex::checkUnlock ()
{
if (!locked) {
std::cerr << "MyMutex already unlocked!" << std::endl;
#ifdef WIN32
DebugBreak ();
#else
raise (SIGTRAP);
#endif
}
locked = false;
}
#endif
#if !TRACE_MYRWMUTEX
void MyReaderLock::acquire ()
{
if (locked) {
return;
}
Glib::Threads::Mutex::Lock lock (mutex.mutex);
if (mutex.writerCount == 0) {
// There's no writer operating, we can increment the writer count which will lock writers.
++mutex.writerCount;
} else if (mutex.readerCount == 0) {
// The writer count is non null, but a reader can be the owner of the writer lock,
// which will be the case if the reader count is not zero too.
while (mutex.writerCount != 0) {
mutex.cond.wait(mutex.mutex);
}
// Then, we can increment the writer count.
++mutex.writerCount;
}
// Finally, we can increment the reader count as well.
++mutex.readerCount;
locked = true;
}
void MyReaderLock::release ()
{
if (!locked) {
return;
}
Glib::Threads::Mutex::Lock lock (mutex.mutex);
// decrement the writer number first...
--mutex.readerCount;
if (mutex.readerCount == 0) {
// ...if no more reader, we decrement the writer count as well...
--mutex.writerCount;
// ...and signal the next waiting reader/writer that it's free
mutex.cond.broadcast ();
}
locked = false;
}
void MyWriterLock::acquire ()
{
if (locked) {
return;
}
Glib::Threads::Mutex::Lock lock (mutex.mutex);
// The writer count is not zero, so we have to wait for it to be zero again...
while (mutex.writerCount != 0) {
mutex.cond.wait (mutex.mutex);
}
// ...then we can increment the writer count.
++mutex.writerCount;
locked = true;
}
void MyWriterLock::release ()
{
if (!locked) {
return;
}
Glib::Threads::Mutex::Lock lock (mutex.mutex);
// Decrement the writer number first...
if (--mutex.writerCount == 0) {
// ...and if the writer count is zero again, we can wake up the next writer or reader.
mutex.cond.broadcast ();
}
locked = false;
}
#else
namespace
{
std::ostream& trace (const char* file, int line)
{
const auto currentThread = Glib::Threads::Thread::self ();
return std::cout << currentThread << ":" << file << ":" << line << ": ";
}
}
void MyReaderLock::acquire (const char* file, int line)
{
if (locked) {
trace (file, line) << "MyReaderLock is already locked." << std::endl;
return;
}
trace (file, line) << "Acquiring MyReaderLock..." << std::endl;
Glib::Threads::Mutex::Lock lock (mutex.mutex);
if (mutex.writerCount == 0) {
// There's no writer operating, we can increment the writer count which will lock writers.
++mutex.writerCount;
} else if (mutex.readerCount == 0) {
// The writer count is non null, but a reader can be the owner of the writer lock,
// which will be the case if the reader count is not zero too.
while (mutex.writerCount != 0) {
trace (file, line) << "Waiting for current owner of MyWriterLock..." << std::endl
<< "\tOwner thread: " << mutex.ownerThread << std::endl
<< "\tLast writer file: " << mutex.lastWriterFile << std::endl
<< "\tLast writer line: " << mutex.lastWriterLine << std::endl;
mutex.cond.wait(mutex.mutex);
}
// Then, we can increment the writer count.
++mutex.writerCount;
mutex.ownerThread = Glib::Threads::Thread::self ();
mutex.lastWriterFile = file;
mutex.lastWriterLine = line;
}
// Finally, we can increment the reader count as well.
++mutex.readerCount;
trace (file, line) << "MyReaderLock is now locked, reader count is " << mutex.readerCount << ", writer count is " << mutex.writerCount << "." << std::endl;
locked = true;
}
void MyReaderLock::release (const char* file, int line)
{
if (!locked) {
trace (file, line) << "MyReaderLock is already unlocked." << std::endl;
return;
}
trace (file, line) << "Releasing MyReaderLock..." << std::endl;
Glib::Threads::Mutex::Lock lock (mutex.mutex);
// decrement the writer number first...
--mutex.readerCount;
if (mutex.readerCount == 0) {
// ...if no more reader, we decrement the writer count as well...
--mutex.writerCount;
// ...and signal the next waiting reader/writer that it's free
mutex.cond.broadcast ();
mutex.ownerThread = nullptr;
mutex.lastWriterFile = "";
mutex.lastWriterLine = 0;
}
trace (file, line) << "MyReaderLock is now unlocked, reader count is " << mutex.readerCount << ", writer count is " << mutex.writerCount << "." << std::endl;
locked = false;
}
void MyWriterLock::acquire (const char* file, int line)
{
if (locked) {
trace (file, line) << "MyWriterLock is already locked." << std::endl;
return;
}
trace (file, line) << "Acquiring MyWriterLock..." << std::endl;
Glib::Threads::Mutex::Lock lock (mutex.mutex);
// The writer count is not zero, so we have to wait for it to be zero again...
while (mutex.writerCount != 0) {
trace (file, line) << "Waiting for current owner of MyWriterLock..." << std::endl
<< "\tOwner thread: " << mutex.ownerThread << std::endl
<< "\tLast writer file: " << mutex.lastWriterFile << std::endl
<< "\tLast writer line: " << mutex.lastWriterLine << std::endl;
mutex.cond.wait (mutex.mutex);
}
// ...then we can increment the writer count.
++mutex.writerCount;
mutex.ownerThread = Glib::Threads::Thread::self ();
mutex.lastWriterFile = file;
mutex.lastWriterLine = line;
trace (file, line) << "MyWriterLock is now locked, reader count is " << mutex.readerCount << ", writer count is " << mutex.writerCount << "." << std::endl;
locked = true;
}
void MyWriterLock::release (const char* file, int line)
{
if (!locked) {
trace (file, line) << "MyWriterLock is already unlocked." << std::endl;
return;
}
trace (file, line) << "Releasing MyWriterLock..." << std::endl;
Glib::Threads::Mutex::Lock lock (mutex.mutex);
// Decrement the writer number first...
if (--mutex.writerCount == 0) {
// ...and if the writer count is zero again, we can wake up the next writer or reader.
mutex.cond.broadcast ();
mutex.ownerThread = nullptr;
mutex.lastWriterFile = "";
mutex.lastWriterLine = 0;
}
trace (file, line) << "MyWriterLock is now unlocked, reader count is " << mutex.readerCount << ", writer count is " << mutex.writerCount << "." << std::endl;
locked = false;
}
#endif

View File

@@ -16,648 +16,294 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>. * along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _THREADUTILS_ #ifndef _THREADUTILS_
#define _THREADUTILS_ #define _THREADUTILS_
#include <glibmm.h> // Uncomment this if you want to bypass the CMakeList options and force the values, but do not commit!
#include <csignal> // for raise()
#include <iostream>
#ifdef WIN32
#include <windows.h>
#endif
#ifdef NDEBUG
// We don't trace mutex
#undef TRACE_MYRWMUTEX
#define TRACE_MYRWMUTEX 0
#endif
// Uncomment this if you want to bypass the CMakeList options and force the values
// Of course, DO NOT COMMIT!
//#undef PROTECT_VECTORS
//#define PROTECT_VECTORS 1
//#undef TRACE_MYRWMUTEX //#undef TRACE_MYRWMUTEX
//#define TRACE_MYRWMUTEX 1 //#define TRACE_MYRWMUTEX 1
//#undef STRICT_MUTEX
//#define STRICT_MUTEX 1
/** #include <glibmm/threads.h>
* @brief Custom Mutex to replace Glib::Threads::Mutex, which behave differently on windows (recursive) and linux (non-recursive), by a recursive and "debugable" one
*
* This implementation will behave like a Glib::Threads::Mutex, but the application will crash instead of freezing.
*
* In Debug builds, a printf will let you know that the MyMutex was already locked
*/
class MyMutex : public Glib::Threads::RecMutex #if STRICT_MUTEX && NDEBUG
{ using MyMutexBase = Glib::Threads::Mutex;
#else
#ifndef NDEBUG using MyMutexBase = Glib::Threads::RecMutex;
private:
bool alreadyLocked;
#endif #endif
/**
* @brief Custom implementation to replace Glib::Threads::Mutex.
*
* Glib::Threads::Mutex shows different behaviour on Windows (recursive) and Linux (non-recursive).
* We therefore use a custom implementation that is optionally recursive and instrumented.
* It will behave like Glib::Threads::RecMutex (STRICT_MUTEX=0) or Glib::Threads::Mutex (STRICT_MUTEX=1).
* Debug builds with strict mutexes, will emit a message and crash immediately upon recursive locking.
*/
class MyMutex : private MyMutexBase
{
public: public:
class MyLock; class MyLock;
#ifndef NDEBUG MyMutex () = default;
MyMutex() : alreadyLocked(false) {} MyMutex (const MyMutex&) = delete;
#else MyMutex& operator= (const MyMutex&) = delete;
MyMutex() {}
#endif
void lock() void lock ();
bool trylock ();
void unlock ();
#if STRICT_MUTEX && !NDEBUG
private:
bool locked = false;
void checkLock ();
void checkUnlock ();
#endif
};
class MyMutex::MyLock
{ {
Glib::Threads::RecMutex::lock(); public:
#ifndef NDEBUG explicit MyLock (MyMutex& mutex);
MyLock (MyMutex& mutex, Glib::Threads::NotLock);
MyLock (MyMutex& mutex, Glib::Threads::TryLock);
if (alreadyLocked) { ~MyLock ();
#ifndef NDEBUG
std::cout << "Warning: MyMutex already locked!" << std::endl; // breakpoint
#endif
#ifndef NDEBUG
#ifdef WIN32
DebugBreak();
#else
raise(SIGTRAP);
#endif
#else
raise(SIGINT);
#endif
}
alreadyLocked = true; MyLock (const MyLock&) = delete;
#endif MyLock& operator= (const MyLock&) = delete;
}
bool trylock() void acquire ();
bool try_acquire ();
void release ();
private:
MyMutex& mutex;
bool locked;
};
/**
* @brief Custom implementation to replace Glib::Threads::RWLock
*/
class MyRWMutex
{ {
if (Glib::Threads::RecMutex::trylock()) { public:
#ifndef NDEBUG MyRWMutex () = default;
MyRWMutex (const MyRWMutex&) = delete;
MyRWMutex& operator= (const MyRWMutex&) = delete;
if (alreadyLocked) { friend class MyReaderLock;
#ifndef NDEBUG friend class MyWriterLock;
std::cout << "Warning: MyMutex already locked!" << std::endl; // breakpoint
private:
Glib::Threads::Mutex mutex;
Glib::Threads::Cond cond;
std::size_t writerCount = 0;
std::size_t readerCount = 0;
#if TRACE_MYRWMUTEX
Glib::Threads::Thread* ownerThread = nullptr;
const char* lastWriterFile = "";
int lastWriterLine = 0;
#endif #endif
#ifndef NDEBUG };
#ifdef WIN32
DebugBreak(); /**
* @brief Custom implementation to replace Glib::Threads::RWLock::ReaderLock
*/
class MyReaderLock
{
public:
~MyReaderLock ();
MyReaderLock (const MyReaderLock&) = delete;
MyReaderLock& operator= (const MyReaderLock&) = delete;
#if !TRACE_MYRWMUTEX
explicit MyReaderLock (MyRWMutex& mutex);
void acquire ();
void release ();
#else #else
raise(SIGTRAP); explicit MyReaderLock (MyRWMutex& mutex, const char* file, int line);
void acquire (const char* file, int line);
void release (const char* file, int line);
#endif #endif
private:
MyRWMutex& mutex;
bool locked;
};
/**
* @brief Custom implementation to replace Glib::Threads::RWLock::WriterLock
*/
class MyWriterLock
{
public:
~MyWriterLock ();
MyWriterLock (const MyWriterLock&) = delete;
MyWriterLock& operator= (const MyWriterLock&) = delete;
#if !TRACE_MYRWMUTEX
explicit MyWriterLock (MyRWMutex& mutex);
void acquire ();
void release ();
#else #else
raise(SIGINT); MyWriterLock (MyRWMutex& mutex, const char* file, int line);
void acquire (const char* file, int line);
void release (const char* file, int line);
#endif
private:
MyRWMutex& mutex;
bool locked;
};
inline void MyMutex::lock ()
{
MyMutexBase::lock ();
#if STRICT_MUTEX && !NDEBUG
checkLock ();
#endif #endif
} }
alreadyLocked = true; inline bool MyMutex::trylock ()
{
if (MyMutexBase::trylock ()) {
#if STRICT_MUTEX && !NDEBUG
checkLock ();
#endif #endif
return true; return true;
} }
return false; return false;
} }
// Warning: the base class of MyMutex is RecMutex, but the mutex is said "unlocked" on first occurrence of "unlock", to avoid overhead. inline void MyMutex::unlock ()
void unlock()
{ {
#ifndef NDEBUG #if STRICT_MUTEX && !NDEBUG
alreadyLocked = false; checkUnlock ();
#endif
Glib::Threads::RecMutex::unlock();
}
};
// Class copied from the Glibmm source code, to provide a workaround of the behavior's difference between Linux and Windows
class MyMutex::MyLock
{
public:
explicit inline MyLock(MyMutex& mutex) : mutex_ (mutex), locked_ (true)
{
mutex_.lock();
}
#ifdef WIN32
inline MyLock(MyMutex& mutex, Glib::NotLock) : mutex_ (mutex), locked_ (false) {}
inline MyLock(MyMutex& mutex, Glib::TryLock) : mutex_ (mutex), locked_ (mutex.trylock()) {}
#else
inline MyLock(MyMutex& mutex, Glib::Threads::NotLock) : mutex_ (mutex), locked_ (false) {}
inline MyLock(MyMutex& mutex, Glib::Threads::TryLock) : mutex_ (mutex), locked_ (mutex.trylock()) {}
#endif
inline ~MyLock()
{
if(locked_) {
mutex_.unlock();
}
}
inline void acquire()
{
mutex_.lock();
locked_ = true;
}
inline bool try_acquire()
{
locked_ = mutex_.trylock();
return locked_;
}
inline void release()
{
mutex_.unlock();
locked_ = false;
}
inline bool locked() const
{
return locked_;
}
private:
MyMutex& mutex_;
bool locked_;
// noncopyable
MyLock(const MyMutex::Lock&);
MyMutex::Lock& operator=(const MyMutex::Lock&);
};
/**
* @brief Custom RWLock with debugging feature, to replace the buggy Glib::RWLock (can have negative reader_count value!)
*
* It may be slower, but thread safe!
*/
class MyRWMutex
{
public:
Glib::Threads::Mutex handlerMutex; // Having a recursive or non-recursive mutex is not important here, so we can use Glib::Threads::Mutex
Glib::Threads::Cond access;
size_t writerCount;
size_t readerCount;
#if TRACE_MYRWMUTEX
Glib::ustring lastWriterFile;
int lastWriterLine;
// Unfortunately, ownerThread may not be the culprit of a deadlock, it can be another concurrent Reader...
void* ownerThread;
MyRWMutex() : writerCount(0), readerCount(0), lastWriterLine(0), ownerThread(NULL) {}
#else
MyRWMutex() : writerCount(0), readerCount(0) {}
#endif
};
/**
* @brief Custom ReaderLock with debugging feature, to replace the buggy Glib::RWLock (can have negative reader_count value!)
*
*/
class MyReaderLock
{
MyRWMutex& rwMutex;
bool locked;
#if TRACE_MYRWMUTEX
static unsigned int readerLockCounter;
int locknumber;
public:
inline MyReaderLock(MyRWMutex& mutex, const char* name, const char* file, const int line) : rwMutex(mutex), locked(false), locknumber(0)
#else
public:
inline MyReaderLock(MyRWMutex & mutex) : rwMutex(mutex)
#endif #endif
MyMutexBase::unlock ();
}
inline MyMutex::MyLock::MyLock (MyMutex& mutex)
: mutex (mutex)
, locked (true)
{ {
// to operate safely mutex.lock();
rwMutex.handlerMutex.lock();
#if TRACE_MYRWMUTEX
locknumber = readerLockCounter++;
void* thread = Glib::Thread::self();
std::cout << thread << "/" << locknumber << ":" << name << " / " << file << " : " << line << " - locking - R";
#endif
if (!rwMutex.writerCount) {
// There's no writer operating, we can increment the writer count which will lock writers
++rwMutex.writerCount;
#if TRACE_MYRWMUTEX
std::cout << " ++ new owner";
#endif
} else {
// The writer count is non null, but we can be the owner of the writer lock
// It will be the case if the reader count is non null too.
if (!rwMutex.readerCount) {
// the mutex is in real write mode, we're waiting to see it null
#if TRACE_MYRWMUTEX
std::cout << " waiting..." << std::endl << "Current writer owner: " << rwMutex.lastWriterFile << " : " << rwMutex.lastWriterLine << std::endl;
#endif
while (rwMutex.writerCount) {
rwMutex.access.wait(rwMutex.handlerMutex);
} }
++rwMutex.writerCount; inline MyMutex::MyLock::MyLock (MyMutex& mutex, Glib::Threads::NotLock)
#if TRACE_MYRWMUTEX : mutex (mutex)
rwMutex.lastWriterFile = file; , locked (false)
rwMutex.lastWriterLine = line; {
rwMutex.ownerThread = thread; }
std::cout << thread << "/" << locknumber << ":" << name << " / " << file << " : " << line << " - locking - R ++ new owner";
#endif inline MyMutex::MyLock::MyLock (MyMutex& mutex, Glib::Threads::TryLock)
: mutex (mutex)
, locked (mutex.trylock ())
{
}
inline MyMutex::MyLock::~MyLock ()
{
if (locked) {
mutex.unlock ();
} }
} }
// then we can increment the reader count inline void MyMutex::MyLock::acquire ()
++rwMutex.readerCount; {
mutex.lock ();
#if TRACE_MYRWMUTEX
std::cout << " - ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
#endif
rwMutex.handlerMutex.unlock();
locked = true; locked = true;
} }
#if TRACE_MYRWMUTEX inline bool MyMutex::MyLock::try_acquire ()
// locks the MyRWMutex with Read access if this MyReaderLock has not already locked it, otherwise return safely
inline void acquire(const char* file, const int line)
#else
// locks the MyRWMutex with Read access if this MyReaderLock has not already locked it, otherwise return safely
inline void acquire()
#endif
{ {
#if TRACE_MYRWMUTEX return locked = mutex.trylock ();
void* thread = Glib::Thread::self();
#endif
if (!locked) {
// to operate safely
rwMutex.handlerMutex.lock();
#if TRACE_MYRWMUTEX
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - R (lock)";
#endif
if (!rwMutex.writerCount) {
// There's no writer operating, we can increment the writer count which will lock writers
++rwMutex.writerCount;
#if TRACE_MYRWMUTEX
std::cout << " ++ new owner";
#endif
} else {
// The writer count is non null, but a reader can be the owner of the writer lock,
// it will be the case if the reader count is non null too.
if (!rwMutex.readerCount) {
// the mutex is in real write mode, we're waiting to see it null
#if TRACE_MYRWMUTEX
std::cout << " waiting..." << std::endl << "Current writer owner: " << rwMutex.lastWriterFile << " : " << rwMutex.lastWriterLine << std::endl;
#endif
while (rwMutex.writerCount) {
rwMutex.access.wait(rwMutex.handlerMutex);
} }
++rwMutex.writerCount; inline void MyMutex::MyLock::release ()
#if TRACE_MYRWMUTEX
rwMutex.lastWriterFile = file;
rwMutex.lastWriterLine = line;
rwMutex.ownerThread = thread;
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - R (lock) ++ new owner";
#endif
}
}
// then we can increment the reader count
++rwMutex.readerCount;
#if TRACE_MYRWMUTEX
std::cout << " - ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
#endif
rwMutex.handlerMutex.unlock();
locked = true;
}
#if TRACE_MYRWMUTEX
else {
std::cout << thread << "/" << locknumber << " / already locked by this object - R (lock)" << std::endl;
}
#endif
}
inline ~MyReaderLock()
{ {
#if TRACE_MYRWMUTEX mutex.unlock ();
void* thread = Glib::Thread::self();
#endif
if (locked) {
// to operate safely
rwMutex.handlerMutex.lock();
// decrement the writer number first
--rwMutex.readerCount;
#if TRACE_MYRWMUTEX
std::cout << thread << "/" << locknumber << " / unlocking - R - ReaderCount: " << rwMutex.readerCount;
#endif
if (!rwMutex.readerCount) {
// no more reader, so we decrement the writer count
--rwMutex.writerCount;
#if TRACE_MYRWMUTEX
rwMutex.lastWriterFile = "";
rwMutex.lastWriterLine = 0;
rwMutex.ownerThread = NULL;
std::cout << " -- new owner possible!" << " >>> ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount;
#endif
// and signal the next waiting reader/writer that it's free
rwMutex.access.broadcast();
}
#if TRACE_MYRWMUTEX
std::cout << std::endl;
#endif
rwMutex.handlerMutex.unlock();
}
#if TRACE_MYRWMUTEX
else {
std::cout << thread << "/" << locknumber << " / already unlocked by this object - R" << std::endl;
}
#endif
}
#if TRACE_MYRWMUTEX
// releases the MyRWMutex with Write access if this MyWriterLock has already locked it, otherwise return safely
inline void release(const char* file, const int line)
#else
// releases the MyRWMutex with Write access if this MyWriterLock has already locked it, otherwise return safely
inline void release()
#endif
{
#if TRACE_MYRWMUTEX
void* thread = Glib::Thread::self();
#endif
if (locked) {
// to operate safely
rwMutex.handlerMutex.lock();
// decrement the writer number first
--rwMutex.readerCount;
#if TRACE_MYRWMUTEX
std::cout << thread << "/" << locknumber << " / unlocking - R (release) - ReaderCount: " << rwMutex.readerCount;
#endif
if (!rwMutex.readerCount) {
// no more reader, so we decrement the writer count
--rwMutex.writerCount;
#if TRACE_MYRWMUTEX
rwMutex.lastWriterFile = "";
rwMutex.lastWriterLine = 0;
rwMutex.ownerThread = NULL;
std::cout << " -- new owner possible!" << " >>> ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount;
#endif
// and signal the next waiting reader/writer that it's free
rwMutex.access.broadcast();
}
#if TRACE_MYRWMUTEX
std::cout << std::endl;
#endif
rwMutex.handlerMutex.unlock();
locked = false; locked = false;
} }
#if TRACE_MYRWMUTEX #if !TRACE_MYRWMUTEX
else {
std::cout << thread << "/" << locknumber << " / already unlocked - R (release)" << std::endl;
}
#endif inline MyReaderLock::MyReaderLock (MyRWMutex& mutex)
} : mutex (mutex)
}; , locked (false)
/**
* @brief Custom WriterLock with debugging feature, to replace the buggy Glib::RWLock (can have negative reader_count value!)
*
*/
class MyWriterLock
{ {
acquire ();
}
MyRWMutex& rwMutex; inline MyWriterLock::MyWriterLock (MyRWMutex& mutex)
bool locked; : mutex (mutex)
, locked (false)
#if TRACE_MYRWMUTEX
static unsigned int writerLockCounter;
int locknumber;
public:
inline MyWriterLock(MyRWMutex& mutex, const char* name, const char* file, const int line) : rwMutex(mutex), locked(false), locknumber(0)
#else
public:
inline MyWriterLock(MyRWMutex & mutex) : rwMutex(mutex)
#endif
{ {
// to operate safely acquire ();
rwMutex.handlerMutex.lock();
#if TRACE_MYRWMUTEX
locknumber = writerLockCounter++;
void* thread = Glib::Thread::self();
std::cout << thread << "/" << locknumber << ":" << name << " / " << file << " : " << line << " - locking - W";
#endif
if (rwMutex.writerCount) {
// The writer count is non null, so we have to wait for it to be null again
#if TRACE_MYRWMUTEX
std::cout << " waiting..." << std::endl << "Current writer owner: " << rwMutex.lastWriterFile << " : " << rwMutex.lastWriterLine << std::endl;
#endif
while (rwMutex.writerCount) {
rwMutex.access.wait(rwMutex.handlerMutex);
} }
#if TRACE_MYRWMUTEX inline MyReaderLock::~MyReaderLock ()
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - W";
#endif
}
// then we can increment the writer count
++rwMutex.writerCount;
#if TRACE_MYRWMUTEX
rwMutex.lastWriterFile = file;
rwMutex.lastWriterLine = line;
rwMutex.ownerThread = thread;
std::cout << " ++ new owner <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
#endif
rwMutex.handlerMutex.unlock();
locked = true;
}
#if TRACE_MYRWMUTEX
// locks the MyRWMutex with Read access if this MyReaderLock has not already locked it, otherwise return safely
inline void acquire(const char* file, const int line)
#else
// locks the MyRWMutex with Read access if this MyReaderLock has not already locked it, otherwise return safely
inline void acquire()
#endif
{ {
#if TRACE_MYRWMUTEX
void* thread = Glib::Thread::self();
#endif
if (!locked) {
// to operate safely
rwMutex.handlerMutex.lock();
#if TRACE_MYRWMUTEX
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - W (lock)";
#endif
if (rwMutex.writerCount) {
// The writer count is non null, so we have to wait for it to be null again
#if TRACE_MYRWMUTEX
std::cout << " waiting..." << std::endl << "Current writer owner: " << rwMutex.lastWriterFile << " : " << rwMutex.lastWriterLine << std::endl;
#endif
while (rwMutex.writerCount) {
rwMutex.access.wait(rwMutex.handlerMutex);
}
#if TRACE_MYRWMUTEX
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - W (lock)";
#endif
}
// then we can increment the reader count
++rwMutex.writerCount;
#if TRACE_MYRWMUTEX
rwMutex.lastWriterFile = file;
rwMutex.lastWriterLine = line;
rwMutex.ownerThread = thread;
std::cout << " ++ new owner <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
#endif
rwMutex.handlerMutex.unlock();
locked = true;
}
#if TRACE_MYRWMUTEX
else {
std::cout << thread << "/" << locknumber << " / already locked by this object - W (lock)" << std::endl;
}
#endif
}
inline ~MyWriterLock()
{
#if TRACE_MYRWMUTEX
void* thread = Glib::Thread::self();
#endif
if (locked) { if (locked) {
// to operate safely release ();
rwMutex.handlerMutex.lock(); }
// decrement the writer number first
--rwMutex.writerCount;
#if TRACE_MYRWMUTEX
std::cout << thread << "/" << locknumber << " / unlocking - W";
#endif
if (!rwMutex.writerCount) {
#if TRACE_MYRWMUTEX
rwMutex.lastWriterFile = "";
rwMutex.lastWriterLine = 0;
rwMutex.ownerThread = NULL;
std::cout << " -- new owner possible!";
#endif
// The writer count is null again, so we can wake up the next writer or reader
rwMutex.access.broadcast();
} }
#if TRACE_MYRWMUTEX inline MyWriterLock::~MyWriterLock ()
std::cout << " <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
#endif
rwMutex.handlerMutex.unlock();
}
#if TRACE_MYRWMUTEX
else {
std::cout << thread << "/" << locknumber << " / already unlocked by this object - W" << std::endl;
}
#endif
}
#if TRACE_MYRWMUTEX
// releases the MyRWMutex with Write access if this MyWriterLock has already locked it, otherwise return safely
inline void release(const char* file, const int line)
#else
// releases the MyRWMutex with Write access if this MyWriterLock has already locked it, otherwise return safely
inline void release()
#endif
{ {
#if TRACE_MYRWMUTEX
void* thread = Glib::Thread::self();
#endif
if (locked) { if (locked) {
// to operate safely release ();
rwMutex.handlerMutex.lock(); }
// decrement the writer number first
--rwMutex.writerCount;
#if TRACE_MYRWMUTEX
std::cout << thread << "/" << locknumber << " / unlocking - W (release)";
#endif
if (!rwMutex.writerCount) {
#if TRACE_MYRWMUTEX
rwMutex.lastWriterFile = "";
rwMutex.lastWriterLine = 0;
rwMutex.ownerThread = NULL;
std::cout << " -- new owner possible!";
#endif
// The writer count is null again, so we can wake up the next writer or reader
rwMutex.access.broadcast();
} }
#if TRACE_MYRWMUTEX #else
std::cout << " <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
#endif
rwMutex.handlerMutex.unlock(); inline MyReaderLock::MyReaderLock (MyRWMutex& mutex, const char* file, int line)
: mutex (mutex)
locked = false; , locked (false)
{
acquire (file, line);
} }
#if TRACE_MYRWMUTEX inline MyWriterLock::MyWriterLock (MyRWMutex& mutex, const char* file, int line)
else { : mutex (mutex)
std::cout << thread << "/" << locknumber << " / already unlocked by this object - W (release)" << std::endl; , locked (false)
{
acquire (file, line);
}
inline MyReaderLock::~MyReaderLock ()
{
if (locked) {
release (__FILE__, __LINE__);
}
}
inline MyWriterLock::~MyWriterLock ()
{
if (locked) {
release (__FILE__, __LINE__);
}
} }
#endif #endif
}
};
#if TRACE_MYRWMUTEX #if TRACE_MYRWMUTEX
#define MYREADERLOCK(ln, e) MyReaderLock ln(e, #e, __FILE__, __LINE__); #define MYREADERLOCK(ln, e) MyReaderLock ln(e, __FILE__, __LINE__);
#define MYWRITERLOCK(ln, e) MyWriterLock ln(e, #e, __FILE__, __LINE__); #define MYWRITERLOCK(ln, e) MyWriterLock ln(e, __FILE__, __LINE__);
#define MYREADERLOCK_ACQUIRE(ln) ln.acquire(__FILE__, __LINE__); #define MYREADERLOCK_ACQUIRE(ln) ln.acquire(__FILE__, __LINE__);
#define MYWRITERLOCK_ACQUIRE(ln) ln.acquire(__FILE__, __LINE__); #define MYWRITERLOCK_ACQUIRE(ln) ln.acquire(__FILE__, __LINE__);
#define MYREADERLOCK_RELEASE(ln) ln.release(__FILE__, __LINE__); #define MYREADERLOCK_RELEASE(ln) ln.release(__FILE__, __LINE__);
@@ -671,20 +317,4 @@ public:
#define MYWRITERLOCK_RELEASE(ln) ln.release(); #define MYWRITERLOCK_RELEASE(ln) ln.release();
#endif #endif
#ifdef PROTECT_VECTORS
#define IFPV_MYREADERLOCK(l, e) MYREADERLOCK(l, e)
#define IFPV_MYWRITERLOCK(l, e) MYWRITERLOCK(l, e)
#define IFPV_MYREADERLOCK_ACQUIRE(l) MYREADERLOCK_ACQUIRE(l)
#define IFPV_MYWRITERLOCK_ACQUIRE(l) MYWRITERLOCK_ACQUIRE(l)
#define IFPV_MYREADERLOCK_RELEASE(l) MYREADERLOCK_RELEASE(l)
#define IFPV_MYWRITERLOCK_RELEASE(l) MYWRITERLOCK_RELEASE(l)
#else
#define IFPV_MYREADERLOCK(l, e)
#define IFPV_MYWRITERLOCK(l, e)
#define IFPV_MYREADERLOCK_ACQUIRE(l)
#define IFPV_MYWRITERLOCK_ACQUIRE(l)
#define IFPV_MYREADERLOCK_RELEASE(l)
#define IFPV_MYWRITERLOCK_RELEASE(l)
#endif
#endif /* _THREADUTILS_ */ #endif /* _THREADUTILS_ */

View File

@@ -59,9 +59,7 @@ ThumbBrowserBase::ThumbBrowserBase ()
void ThumbBrowserBase::scrollChanged () void ThumbBrowserBase::scrollChanged ()
{ {
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
for (size_t i = 0; i < fd.size(); i++) { for (size_t i = 0; i < fd.size(); i++) {
fd[i]->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); fd[i]->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value()));
@@ -204,9 +202,7 @@ void ThumbBrowserBase::selectPrev (int distance, bool enlarge)
getScrollPosition (h, v); getScrollPosition (h, v);
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
if (!selected.empty ()) { if (!selected.empty ()) {
std::vector<ThumbBrowserEntryBase*>::iterator front = std::find (fd.begin (), fd.end (), selected.front ()); std::vector<ThumbBrowserEntryBase*>::iterator front = std::find (fd.begin (), fd.end (), selected.front ());
@@ -261,9 +257,7 @@ void ThumbBrowserBase::selectPrev (int distance, bool enlarge)
} }
} }
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
#endif
selectionChanged (); selectionChanged ();
} }
@@ -276,9 +270,7 @@ void ThumbBrowserBase::selectNext (int distance, bool enlarge)
getScrollPosition (h, v); getScrollPosition (h, v);
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
if (!selected.empty ()) { if (!selected.empty ()) {
std::vector<ThumbBrowserEntryBase*>::iterator front = std::find (fd.begin (), fd.end (), selected.front ()); std::vector<ThumbBrowserEntryBase*>::iterator front = std::find (fd.begin (), fd.end (), selected.front ());
@@ -333,9 +325,7 @@ void ThumbBrowserBase::selectNext (int distance, bool enlarge)
} }
} }
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
#endif
selectionChanged (); selectionChanged ();
} }
@@ -348,9 +338,7 @@ void ThumbBrowserBase::selectFirst (bool enlarge)
getScrollPosition (h, v); getScrollPosition (h, v);
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
if (!fd.empty ()) { if (!fd.empty ()) {
// find first unfiltered entry // find first unfiltered entry
@@ -401,9 +389,7 @@ void ThumbBrowserBase::selectFirst (bool enlarge)
} }
} }
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
#endif
selectionChanged (); selectionChanged ();
} }
@@ -416,9 +402,7 @@ void ThumbBrowserBase::selectLast (bool enlarge)
getScrollPosition (h, v); getScrollPosition (h, v);
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
if (!fd.empty ()) { if (!fd.empty ()) {
// find last unfiltered entry // find last unfiltered entry
@@ -471,9 +455,7 @@ void ThumbBrowserBase::selectLast (bool enlarge)
} }
} }
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
#endif
selectionChanged (); selectionChanged ();
} }
@@ -544,10 +526,7 @@ void ThumbBrowserBase::configScrollBars ()
void ThumbBrowserBase::arrangeFiles () void ThumbBrowserBase::arrangeFiles ()
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
// GUI already locked by ::redraw, the only caller of this method for now. // GUI already locked by ::redraw, the only caller of this method for now.
// We could lock it one more time, there's no harm excepted (negligible) speed penalty // We could lock it one more time, there's no harm excepted (negligible) speed penalty
@@ -608,9 +587,7 @@ void ThumbBrowserBase::arrangeFiles ()
currx += maxw; currx += maxw;
} }
#if PROTECT_VECTORS
MYREADERLOCK_RELEASE(l); MYREADERLOCK_RELEASE(l);
#endif
// This will require a Writer access // This will require a Writer access
resizeThumbnailArea (currx, numOfRows * rowHeight); resizeThumbnailArea (currx, numOfRows * rowHeight);
} else { } else {
@@ -687,9 +664,7 @@ void ThumbBrowserBase::arrangeFiles ()
} }
} }
#if PROTECT_VECTORS
MYREADERLOCK_RELEASE(l); MYREADERLOCK_RELEASE(l);
#endif
// This will require a Writer access // This will require a Writer access
resizeThumbnailArea (colsWidth, curry); resizeThumbnailArea (colsWidth, curry);
} }
@@ -747,9 +722,7 @@ bool ThumbBrowserBase::Internal::on_query_tooltip (int x, int y, bool keyboard_t
Glib::ustring ttip = ""; Glib::ustring ttip = "";
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, parent->entryRW); MYREADERLOCK(l, parent->entryRW);
#endif
for (size_t i = 0; i < parent->fd.size(); i++) for (size_t i = 0; i < parent->fd.size(); i++)
if (parent->fd[i]->drawable && parent->fd[i]->inside (x, y)) { if (parent->fd[i]->drawable && parent->fd[i]->inside (x, y)) {
@@ -826,7 +799,7 @@ void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType typ
bool handled = false; bool handled = false;
{ {
IFPV_MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
for (size_t i = 0; i < fd.size(); i++) for (size_t i = 0; i < fd.size(); i++)
if (fd[i]->drawable) { if (fd[i]->drawable) {
@@ -844,7 +817,7 @@ void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType typ
} }
{ {
IFPV_MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
if (selected.size() == 1 && type == GDK_2BUTTON_PRESS && button == 1) { if (selected.size() == 1 && type == GDK_2BUTTON_PRESS && button == 1) {
doubleClicked (selected[0]); doubleClicked (selected[0]);
@@ -857,18 +830,18 @@ void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType typ
selectSingle (fileDescr); selectSingle (fileDescr);
lastClicked = fileDescr; lastClicked = fileDescr;
IFPV_MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
selectionChanged (); selectionChanged ();
} else if (fileDescr && button == 3 && type == GDK_BUTTON_PRESS) { } else if (fileDescr && button == 3 && type == GDK_BUTTON_PRESS) {
if (!fileDescr->selected) { if (!fileDescr->selected) {
selectSingle (fileDescr); selectSingle (fileDescr);
lastClicked = fileDescr; lastClicked = fileDescr;
IFPV_MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
selectionChanged (); selectionChanged ();
} }
IFPV_MYWRITERLOCK_RELEASE(l); MYWRITERLOCK_RELEASE(l);
rightClicked (fileDescr); rightClicked (fileDescr);
} }
} // end of MYWRITERLOCK(l, entryRW); } // end of MYWRITERLOCK(l, entryRW);
@@ -895,9 +868,7 @@ bool ThumbBrowserBase::Internal::on_draw(const ::Cairo::RefPtr< Cairo::Context>
context->set_font_description (style->get_font()); context->set_font_description (style->get_font());
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, parent->entryRW); MYWRITERLOCK(l, parent->entryRW);
#endif
for (size_t i = 0; i < parent->fd.size() && !dirty; i++) { // if dirty meanwhile, cancel and wait for next redraw for (size_t i = 0; i < parent->fd.size() && !dirty; i++) { // if dirty meanwhile, cancel and wait for next redraw
if (!parent->fd[i]->drawable || !parent->fd[i]->insideWindow (0, 0, w, h)) { if (!parent->fd[i]->drawable || !parent->fd[i]->insideWindow (0, 0, w, h)) {
@@ -918,21 +889,15 @@ bool ThumbBrowserBase::Internal::on_button_release_event (GdkEventButton* event)
int w = get_width(); int w = get_width();
int h = get_height(); int h = get_height();
#if PROTECT_VECTORS
MYREADERLOCK(l, parent->entryRW); MYREADERLOCK(l, parent->entryRW);
#endif
for (size_t i = 0; i < parent->fd.size(); i++) for (size_t i = 0; i < parent->fd.size(); i++)
if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h)) { if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h)) {
ThumbBrowserEntryBase* tbe = parent->fd[i]; ThumbBrowserEntryBase* tbe = parent->fd[i];
#if PROTECT_VECTORS
MYREADERLOCK_RELEASE(l); MYREADERLOCK_RELEASE(l);
#endif
// This will require a Writer access... // This will require a Writer access...
tbe->releaseNotify (event->button, event->type, event->state, (int)event->x, (int)event->y); tbe->releaseNotify (event->button, event->type, event->state, (int)event->x, (int)event->y);
#if PROTECT_VECTORS
MYREADERLOCK_ACQUIRE(l); MYREADERLOCK_ACQUIRE(l);
#endif
} }
return true; return true;
@@ -944,15 +909,10 @@ bool ThumbBrowserBase::Internal::on_motion_notify_event (GdkEventMotion* event)
int w = get_width(); int w = get_width();
int h = get_height(); int h = get_height();
#if PROTECT_VECTORS
MYREADERLOCK(l, parent->entryRW); MYREADERLOCK(l, parent->entryRW);
#endif
for (size_t i = 0; i < parent->fd.size(); i++) for (size_t i = 0; i < parent->fd.size(); i++)
if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h)) { if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h)) {
/*#if PROTECT_VECTORS
MYREADERLOCK_RELEASE(l); // motionNotify calls the queue, which locks
#endif*/
parent->fd[i]->motionNotify ((int)event->x, (int)event->y); parent->fd[i]->motionNotify ((int)event->x, (int)event->y);
} }
@@ -1004,9 +964,7 @@ void ThumbBrowserBase::zoomChanged (bool zoomIn)
saveThumbnailHeight(newHeight); saveThumbnailHeight(newHeight);
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
for (size_t i = 0; i < fd.size(); i++) { for (size_t i = 0; i < fd.size(); i++) {
fd[i]->resize (previewHeight); fd[i]->resize (previewHeight);
@@ -1024,9 +982,7 @@ void ThumbBrowserBase::refreshThumbImages ()
int previewHeight = getThumbnailHeight(); int previewHeight = getThumbnailHeight();
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
for (size_t i = 0; i < fd.size(); i++) { for (size_t i = 0; i < fd.size(); i++) {
fd[i]->resize (previewHeight); fd[i]->resize (previewHeight);
@@ -1038,9 +994,7 @@ void ThumbBrowserBase::refreshThumbImages ()
void ThumbBrowserBase::refreshQuickThumbImages () void ThumbBrowserBase::refreshQuickThumbImages ()
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
for (size_t i = 0; i < fd.size(); ++i) { for (size_t i = 0; i < fd.size(); ++i) {
fd[i]->refreshQuickThumbnailImage (); fd[i]->refreshQuickThumbnailImage ();
@@ -1052,9 +1006,7 @@ void ThumbBrowserBase::refreshEditedState (const std::set<Glib::ustring>& efiles
editedFiles = efiles; editedFiles = efiles;
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
for (size_t i = 0; i < fd.size(); i++) { for (size_t i = 0; i < fd.size(); i++) {
fd[i]->framed = editedFiles.find (fd[i]->filename) != editedFiles.end(); fd[i]->framed = editedFiles.find (fd[i]->filename) != editedFiles.end();
@@ -1077,9 +1029,8 @@ void ThumbBrowserBase::enableTabMode(bool enable)
arrangement = enable ? ThumbBrowserBase::TB_Horizontal : ThumbBrowserBase::TB_Vertical; arrangement = enable ? ThumbBrowserBase::TB_Horizontal : ThumbBrowserBase::TB_Vertical;
if ((!options.sameThumbSize && (options.thumbSizeTab != options.thumbSize)) || (options.showFileNames || options.filmStripShowFileNames)) { if ((!options.sameThumbSize && (options.thumbSizeTab != options.thumbSize)) || (options.showFileNames || options.filmStripShowFileNames)) {
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW); MYWRITERLOCK(l, entryRW);
#endif
for (size_t i = 0; i < fd.size(); i++) { for (size_t i = 0; i < fd.size(); i++) {
fd[i]->resize (getThumbnailHeight()); fd[i]->resize (getThumbnailHeight());
@@ -1091,22 +1042,16 @@ void ThumbBrowserBase::enableTabMode(bool enable)
// Scroll to selected position if going into ribbon mode or back // Scroll to selected position if going into ribbon mode or back
// Tab mode is horizontal, file browser is vertical // Tab mode is horizontal, file browser is vertical
{ {
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
if (!selected.empty()) { if (!selected.empty()) {
if (enable) { if (enable) {
double h = selected[0]->getStartX(); double h = selected[0]->getStartX();
#if PROTECT_VECTORS
MYREADERLOCK_RELEASE(l); MYREADERLOCK_RELEASE(l);
#endif
hscroll.set_value (min(h, hscroll.get_adjustment()->get_upper())); hscroll.set_value (min(h, hscroll.get_adjustment()->get_upper()));
} else { } else {
double v = selected[0]->getStartY(); double v = selected[0]->getStartY();
#if PROTECT_VECTORS
MYREADERLOCK_RELEASE(l); MYREADERLOCK_RELEASE(l);
#endif
vscroll.set_value (min(v, vscroll.get_adjustment()->get_upper())); vscroll.set_value (min(v, vscroll.get_adjustment()->get_upper()));
} }
} }
@@ -1135,9 +1080,7 @@ int ThumbBrowserBase::getEffectiveHeight()
{ {
int h = hscroll.get_height() + 2; // have 2 pixels rounding error for scroll bars to appear int h = hscroll.get_height() + 2; // have 2 pixels rounding error for scroll bars to appear
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW); MYREADERLOCK(l, entryRW);
#endif
// Filtered items do not change in size, so take a non-filtered // Filtered items do not change in size, so take a non-filtered
for (size_t i = 0; i < fd.size(); i++) for (size_t i = 0; i < fd.size(); i++)

View File

@@ -352,10 +352,7 @@ void ThumbBrowserEntryBase::getTextSizes (int& infow, int& infoh)
void ThumbBrowserEntryBase::resize (int h) void ThumbBrowserEntryBase::resize (int h)
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, lockRW); MYWRITERLOCK(l, lockRW);
#endif
height = h; height = h;
int old_preh = preh, old_width = width; int old_preh = preh, old_width = width;
@@ -474,9 +471,7 @@ void ThumbBrowserEntryBase::draw (Cairo::RefPtr<Cairo::Context> cc)
return; return;
} }
#if PROTECT_VECTORS
MYREADERLOCK(l, lockRW); // No resizes, position moves etc. inbetween MYREADERLOCK(l, lockRW); // No resizes, position moves etc. inbetween
#endif
int bbWidth, bbHeight; int bbWidth, bbHeight;
@@ -509,10 +504,7 @@ void ThumbBrowserEntryBase::draw (Cairo::RefPtr<Cairo::Context> cc)
void ThumbBrowserEntryBase::setPosition (int x, int y, int w, int h) void ThumbBrowserEntryBase::setPosition (int x, int y, int w, int h)
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, lockRW); MYWRITERLOCK(l, lockRW);
#endif
exp_width = w; exp_width = w;
exp_height = h; exp_height = h;
@@ -526,10 +518,7 @@ void ThumbBrowserEntryBase::setPosition (int x, int y, int w, int h)
void ThumbBrowserEntryBase::setOffset (int x, int y) void ThumbBrowserEntryBase::setOffset (int x, int y)
{ {
#if PROTECT_VECTORS
MYWRITERLOCK(l, lockRW); MYWRITERLOCK(l, lockRW);
#endif
ofsX = -x; ofsX = -x;
ofsY = -y; ofsY = -y;