diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fc629ec9..6799d7dcd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,7 @@ option (WITH_BZIP "Build with Bzip2 support" ON) option (WITH_MYFILE_MMAP "Build using memory mapped file" 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 (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) @@ -162,6 +163,13 @@ if (NOT BUILD_BUNDLE AND message (FATAL_ERROR "The paths has to be absolute or use -DBUILD_BUNDLE=ON") endif () +# MyMutex +if (STRICT_MUTEX OR UPPER_CMAKE_BUILD_TYPE STREQUAL "DEBUG") + add_definitions (-DSTRICT_MUTEX=1) +else (STRICT_MUTEX OR UPPER_CMAKE_BUILD_TYPE STREQUAL "DEBUG") + add_definitions (-DSTRICT_MUTEX=0) +endif (STRICT_MUTEX OR UPPER_CMAKE_BUILD_TYPE STREQUAL "DEBUG") + # MyRWMutex if (PROTECT_VECTORS) add_definitions (-DPROTECT_VECTORS=1) diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index 7b6985b99..39f542d0c 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -27,6 +27,7 @@ #include #include +#include "../rtgui/threadutils.h" //#include "bilateral2.h" #include "gauss.h" @@ -87,8 +88,8 @@ namespace rtengine { void ImProcFunctions::RGB_denoise(Imagefloat * src, Imagefloat * dst, bool isRAW, const procparams::DirPyrDenoiseParams & dnparams, const procparams::DefringeParams & defringe, const double expcomp) { - static Glib::Mutex FftwMutex; - Glib::Mutex::Lock lock(FftwMutex); + static MyMutex FftwMutex; + MyMutex::MyLock lock(FftwMutex); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/rtengine/alignedbuffer.h b/rtengine/alignedbuffer.h index 7a1c62d17..61fa08dff 100644 --- a/rtengine/alignedbuffer.h +++ b/rtengine/alignedbuffer.h @@ -22,6 +22,7 @@ #include #include #include +#include "../rtgui/threadutils.h" // Aligned buffer that should be faster template class AlignedBuffer { @@ -107,7 +108,7 @@ public: // Multi processor version, use with OpenMP template class AlignedBufferMP { private: - Glib::Mutex mtx; + MyMutex mtx; std::vector*> buffers; size_t size; @@ -121,7 +122,7 @@ public: } AlignedBuffer* acquire() { - Glib::Mutex::Lock lock(mtx); + MyMutex::MyLock lock(mtx); // Find available buffer for (int i;i* buffer) { - Glib::Mutex::Lock lock(mtx); + MyMutex::MyLock lock(mtx); buffer->inUse=false; } diff --git a/rtengine/cplx_wavelet_level.h b/rtengine/cplx_wavelet_level.h index 756b5ce8f..a89b91af6 100644 --- a/rtengine/cplx_wavelet_level.h +++ b/rtengine/cplx_wavelet_level.h @@ -556,17 +556,17 @@ namespace rtengine { for (int i=0; igetTag(TagCalibrationIlluminant1); iLightSource1 = (tag!=NULL ? tag->toInt(0,SHORT) : -1); - tag = tagDir->getTag(TagCalibrationIlluminant2); iLightSource2 = (tag!=NULL ? tag->toInt(0,SHORT) : -1); + Tag* tag = tagDir->getTag(TagCalibrationIlluminant1); iLightSource1 = (tag!=NULL ? tag->toInt(0,rtexif::SHORT) : -1); + tag = tagDir->getTag(TagCalibrationIlluminant2); iLightSource2 = (tag!=NULL ? tag->toInt(0,rtexif::SHORT) : -1); bool hasSecondHueSat = tagDir->getTag(TagProfileHueSatMapData2)!=NULL; // some profiles have two matrices, but just one huesat @@ -495,8 +495,8 @@ DCPStore* DCPStore::getInstance() static DCPStore* instance_ = 0; if ( instance_ == 0 ) { - static Glib::Mutex smutex_; - Glib::Mutex::Lock lock(smutex_); + static MyMutex smutex_; + MyMutex::MyLock lock(smutex_); if ( instance_ == 0 ) { instance_ = new DCPStore(); @@ -507,7 +507,7 @@ DCPStore* DCPStore::getInstance() // Reads all profiles from the given profiles dir void DCPStore::init (Glib::ustring rtProfileDir) { - Glib::Mutex::Lock lock(mtx); + MyMutex::MyLock lock(mtx); fileStdProfiles.clear(); @@ -550,7 +550,7 @@ void DCPStore::init (Glib::ustring rtProfileDir) { } DCPProfile* DCPStore::getProfile (Glib::ustring filename, bool isRTProfile) { - Glib::Mutex::Lock lock(mtx); + MyMutex::MyLock lock(mtx); std::map::iterator r = profileCache.find (filename); if (r!=profileCache.end()) return r->second; diff --git a/rtengine/dcp.h b/rtengine/dcp.h index 53208f3ff..b7466dbec 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -22,6 +22,7 @@ #include "imagefloat.h" #include "curves.h" +#include "../rtgui/threadutils.h" #include #include #include @@ -65,7 +66,7 @@ namespace rtengine { }; class DCPStore { - Glib::Mutex mtx; + MyMutex mtx; // these contain standard profiles from RT. keys are all in uppercase, file path is value std::map fileStdProfiles; diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 03fdbbdda..a923d7479 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -1,4 +1,3 @@ -/* /* * This file is part of RawTherapee. * @@ -53,15 +52,15 @@ Crop::~Crop () { } void Crop::setListener (DetailedCropListener* il) { - // We can make reads in the IF, because the mProcessing lock is only needed for change - if (cropImageListener!=il) { - Glib::Mutex::Lock lock(cropMutex); - cropImageListener = il; - } -} + // We can make reads in the IF, because the mProcessing lock is only needed for change + if (cropImageListener!=il) { + MyMutex::MyLock lock(cropMutex); + cropImageListener = il; + } +} void Crop::update (int todo) { - Glib::Mutex::Lock lock(cropMutex); + MyMutex::MyLock lock(cropMutex); ProcParams& params = parent->params; @@ -89,7 +88,7 @@ void Crop::update (int todo) { bool needstransform = parent->ipf.needsTransform(); if (todo & (M_INIT|M_LINDENOISE)) { - Glib::Mutex::Lock lock(parent->minit); // Also used in improccoord + MyMutex::MyLock lock(parent->minit); // Also used in improccoord int tr = TR_NONE; if (params.coarse.rotate==90) tr |= TR_R90; diff --git a/rtengine/dcrop.h b/rtengine/dcrop.h index 344226f72..b5881546c 100644 --- a/rtengine/dcrop.h +++ b/rtengine/dcrop.h @@ -26,6 +26,7 @@ #include "image16.h" #include "imagesource.h" #include "procevents.h" +#include "../rtgui/threadutils.h" namespace rtengine { @@ -36,11 +37,11 @@ class ImProcCoordinator; class Crop : public DetailedCrop { protected: - Imagefloat* origCrop, *baseCrop; + Imagefloat* origCrop, *baseCrop; Imagefloat* *resizeCrop, *transCrop; LabImage *laboCrop, *labnCrop; Image8 *cropImg; // permanently allocated in RAM and only renewed on size changes - CieImage *cieCrop; + CieImage *cieCrop; float** cbuffer; float * cbuf_real; SHMap* cshmap; @@ -51,28 +52,27 @@ class Crop : public DetailedCrop { int trafx, trafy, trafw, trafh; // the size and position to get from the imagesource that is transformed to the requested crop area int rqcropx, rqcropy, rqcropw, rqcroph; // size of the requested detail crop image (the image might be smaller) (without border) int borderRequested, upperBorder, leftBorder; - bool cropAllocated; DetailedCropListener* cropImageListener; - - Glib::Mutex cropMutex; + + MyMutex cropMutex; ImProcCoordinator* parent; bool setCropSizes (int cx, int cy, int cw, int ch, int skip, bool internal); void freeAll (); - + public: - Crop (ImProcCoordinator* parent); - virtual ~Crop (); + Crop (ImProcCoordinator* parent); + virtual ~Crop (); bool hasListener () { return cropImageListener; } void update (int todo); void setWindow (int cx, int cy, int cw, int ch, int skip) { setCropSizes (cx, cy, cw, ch, skip, false); } - - bool tryUpdate (); // First try, only make fullUpdate if this returns false - void fullUpdate (); // called via thread - + + bool tryUpdate (); // First try, only make fullUpdate if this returns false + void fullUpdate (); // called via thread + void setListener (DetailedCropListener* il); void destroy () {} int get_skip () { return skip;} diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index b5ceb2e81..6a9c113cf 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -16,12 +16,12 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "iccstore.h" #ifdef WIN32 #include #else #include #endif +#include "iccstore.h" #include "iccmatrices.h" #include #include "safegtk.h" @@ -62,7 +62,7 @@ std::vector getWorkingProfiles () { std::vector ICCStore::getOutputProfiles () { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); std::vector res; for (std::map::iterator i=fileProfiles.begin(); i!=fileProfiles.end(); i++){ @@ -83,8 +83,8 @@ ICCStore::getInstance(void) static ICCStore* instance_ = 0; if ( instance_ == 0 ) { - static Glib::Mutex smutex_; - Glib::Mutex::Lock lock(smutex_); + static MyMutex smutex_; + MyMutex::MyLock lock(smutex_); if ( instance_ == 0 ) { instance_ = new ICCStore(); @@ -153,7 +153,7 @@ cmsHPROFILE ICCStore::workingSpaceGamma (Glib::ustring name) { cmsHPROFILE ICCStore::getProfile (Glib::ustring name) { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); std::map::iterator r = fileProfiles.find (name); if (r!=fileProfiles.end()) @@ -176,7 +176,7 @@ cmsHPROFILE ICCStore::getProfile (Glib::ustring name) { cmsHPROFILE ICCStore::getStdProfile (Glib::ustring name) { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); std::map::iterator r = fileStdProfiles.find (name.uppercase()); @@ -187,7 +187,7 @@ cmsHPROFILE ICCStore::getStdProfile (Glib::ustring name) { ProfileContent ICCStore::getContent (Glib::ustring name) { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); return fileProfileContents[name]; } @@ -195,7 +195,7 @@ ProfileContent ICCStore::getContent (Glib::ustring name) { // Reads all profiles from the given profiles dir void ICCStore::init (Glib::ustring usrICCDir, Glib::ustring rtICCDir) { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); // fileProfiles.clear(); diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index 18755d73c..f6381f54f 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -23,6 +23,7 @@ #include #include #include +#include "../rtgui/threadutils.h" namespace rtengine { @@ -61,7 +62,7 @@ class ICCStore { cmsHPROFILE xyz; cmsHPROFILE srgb; - Glib::Mutex mutex_; + MyMutex mutex_; ICCStore (); void loadICCs(Glib::ustring rootDirName, bool nameUpper, std::map& resultProfiles, std::map &resultProfileContents); diff --git a/rtengine/iimage.h b/rtengine/iimage.h index c8ce9793f..e33b9b696 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -23,6 +23,7 @@ #include #include #include +#include "../rtgui/threadutils.h" #include "rt_math.h" #include "alignedbuffer.h" #include "imagedimensions.h" @@ -1021,7 +1022,7 @@ namespace rtengine { virtual ~IImage() {} /** Returns a mutex that can is useful in many situations. No image operations shuold be performed without locking this mutex. * @return The mutex */ - virtual Glib::Mutex& getMutex ()=0; + virtual MyMutex& getMutex ()=0; virtual cmsHPROFILE getProfile ()=0; /** Returns the bits per pixel of the image. * @return The bits per pixel of the image */ diff --git a/rtengine/image16.h b/rtengine/image16.h index 30381dc73..bc4e1aa6b 100644 --- a/rtengine/image16.h +++ b/rtengine/image16.h @@ -51,7 +51,7 @@ class Image16 : public IImage16, public ImageIO { virtual void setScanline (int row, unsigned char* buffer, int bps, float *minValue=NULL, float *maxValue=NULL); // functions inherited from IImage16: - virtual Glib::Mutex& getMutex () { return mutex (); } + virtual MyMutex& getMutex () { return mutex (); } virtual cmsHPROFILE getProfile () { return getEmbeddedProfile (); } virtual int getBitsPerPixel () { return 8*sizeof(unsigned short); } virtual int saveToFile (Glib::ustring fname) { return save (fname); } diff --git a/rtengine/image8.h b/rtengine/image8.h index 9b5a26edb..570e1d539 100644 --- a/rtengine/image8.h +++ b/rtengine/image8.h @@ -46,7 +46,7 @@ class Image8 : public IImage8, public ImageIO { virtual void setScanline (int row, unsigned char* buffer, int bps, float *minValue=NULL, float *maxValue=NULL); // functions inherited from IImage*: - virtual Glib::Mutex& getMutex () { return mutex (); } + virtual MyMutex& getMutex () { return mutex (); } virtual cmsHPROFILE getProfile () { return getEmbeddedProfile (); } virtual int getBitsPerPixel () { return 8*sizeof(unsigned char); } virtual int saveToFile (Glib::ustring fname) { return save (fname); } diff --git a/rtengine/imagefloat.h b/rtengine/imagefloat.h index fd372965d..9f99384c5 100644 --- a/rtengine/imagefloat.h +++ b/rtengine/imagefloat.h @@ -55,7 +55,7 @@ class Imagefloat : public IImagefloat, public ImageIO { virtual void setScanline (int row, unsigned char* buffer, int bps, float *minValue=NULL, float *maxValue=NULL); // functions inherited from IImagefloat: - virtual Glib::Mutex& getMutex () { return mutex (); } + virtual MyMutex& getMutex () { return mutex (); } virtual cmsHPROFILE getProfile () { return getEmbeddedProfile (); } virtual int getBitsPerPixel () { return 8*sizeof(float); } virtual int saveToFile (Glib::ustring fname) { return save (fname); } diff --git a/rtengine/imageio.h b/rtengine/imageio.h index 4a6f7114b..8d05d401c 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -34,6 +34,7 @@ #include "../rtexif/rtexif.h" #include "imagedimensions.h" #include "iimage.h" +#include "../rtgui/threadutils.h" namespace rtengine { @@ -69,7 +70,7 @@ class ImageIO : virtual public ImageDatas { procparams::ExifPairs exifChange; IptcData* iptc; const rtexif::TagDirectory* exifRoot; - Glib::Mutex imutex; + MyMutex imutex; IIOSampleFormat sampleFormat; IIOSampleArrangement sampleArrangement; @@ -122,7 +123,7 @@ class ImageIO : virtual public ImageDatas { void setMetadata (const rtexif::TagDirectory* eroot); void setMetadata (const rtexif::TagDirectory* eroot, const rtengine::procparams::ExifPairs& exif, const rtengine::procparams::IPTCPairs& iptcc); void setOutputProfile (char* pdata, int plen); - Glib::Mutex& mutex () { return imutex; } + MyMutex& mutex () { return imutex; } }; } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 69a4f54ec..0495261e5 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -177,7 +177,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { if (todo & (M_INIT|M_LINDENOISE)) { - Glib::Mutex::Lock lock(minit); // Also used in crop window + MyMutex::MyLock lock(minit); // Also used in crop window imgsrc->HLRecovery_Global( params.hlrecovery ); // this handles Color HLRecovery @@ -623,7 +623,7 @@ bool ImProcCoordinator::getAutoWB (double& temp, double& green, double equal) { if (imgsrc) { if (lastAwbEqual != equal) { - Glib::Mutex::Lock lock(minit); // Also used in crop window + MyMutex::MyLock lock(minit); // Also used in crop window double rm, gm, bm; imgsrc->getAutoWBMultipliers(rm, gm, bm); if (rm != -1) { diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 481319a8e..3d2798210 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -27,6 +27,7 @@ #include "procevents.h" #include "dcrop.h" #include "LUT.h" +#include "../rtgui/threadutils.h" namespace rtengine { @@ -123,7 +124,7 @@ class ImProcCoordinator : public StagedImageProcessor { bool resultValid; - Glib::Mutex minit; + MyMutex minit; void progress (Glib::ustring str, int pr); void reallocAll (); @@ -131,13 +132,13 @@ class ImProcCoordinator : public StagedImageProcessor { void setScale (int prevscale); void updatePreviewImage (int todo, Crop* cropCall= NULL); - Glib::Mutex mProcessing; + MyMutex mProcessing; ProcParams params; // members of the updater: Glib::Thread* thread; - Glib::Mutex updaterThreadStart; - Glib::Mutex paramsUpdateMutex; + MyMutex updaterThreadStart; + MyMutex paramsUpdateMutex; int changeSinceLast; bool updaterRunning; ProcParams nextParams; diff --git a/rtengine/init.cc b/rtengine/init.cc index b5e79092a..c1fb991ca 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -25,12 +25,13 @@ #include "ffmanager.h" #include "rtthumbnail.h" #include "../rtgui/profilestore.h" +#include "../rtgui/threadutils.h" namespace rtengine { const Settings* settings; -Glib::Mutex* lcmsMutex = NULL; +MyMutex* lcmsMutex = NULL; int init (const Settings* s, Glib::ustring baseDir) { @@ -46,7 +47,7 @@ int init (const Settings* s, Glib::ustring baseDir) { ImProcFunctions::initCache (); Thumbnail::initGamma (); delete lcmsMutex; - lcmsMutex = new Glib::Mutex; + lcmsMutex = new MyMutex; dfm.init( s->darkFramesPath ); ffm.init( s->flatFieldsPath ); return 0; diff --git a/rtengine/lcp.cc b/rtengine/lcp.cc index 3982675bf..4a0c64ed7 100644 --- a/rtengine/lcp.cc +++ b/rtengine/lcp.cc @@ -629,8 +629,8 @@ LCPStore* LCPStore::getInstance() static LCPStore* instance_ = 0; if ( instance_ == 0 ) { - static Glib::Mutex smutex_; - Glib::Mutex::Lock lock(smutex_); + static MyMutex smutex_; + MyMutex::MyLock lock(smutex_); if ( instance_ == 0 ) { instance_ = new LCPStore(); @@ -642,7 +642,7 @@ LCPStore* LCPStore::getInstance() LCPProfile* LCPStore::getProfile (Glib::ustring filename) { if (filename.length()==0 || !isValidLCPFileName(filename)) return NULL; - Glib::Mutex::Lock lock(mtx); + MyMutex::MyLock lock(mtx); std::map::iterator r = profileCache.find (filename); if (r!=profileCache.end()) return r->second; @@ -676,4 +676,4 @@ Glib::ustring LCPStore::getDefaultCommonDirectory() const { // TODO: Add Mac paths here return dir; -} \ No newline at end of file +} diff --git a/rtengine/lcp.h b/rtengine/lcp.h index 71d71c3e5..690ec0bb5 100644 --- a/rtengine/lcp.h +++ b/rtengine/lcp.h @@ -21,6 +21,7 @@ #define _LCP_ #include "imagefloat.h" +#include "../rtgui/threadutils.h" #include #include #include @@ -92,7 +93,7 @@ namespace rtengine { }; class LCPStore { - Glib::Mutex mtx; + MyMutex mtx; // Maps file name to profile as cache std::map profileCache; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index d02f169de..5ec3543d5 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -205,7 +205,7 @@ void RawImageSource::transformRect (PreviewProps pp, int tran, int &ssx1, int &s void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, HRecParams hrp, ColorManagementParams cmp, RAWParams raw ) { - Glib::Mutex::Lock lock(getImageMutex); + MyMutex::MyLock lock(getImageMutex); tran = defTransform (tran); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 2bc9beb6c..565b26d94 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -28,6 +28,7 @@ #include "color.h" #include "iimage.h" #include "../rtgui/cacheimagedata.h" +#include "../rtgui/threadutils.h" #define HR_SCALE 2 @@ -68,7 +69,7 @@ class RawImageSource : public ImageSource { static void colorSpaceConversion (Imagefloat* im, ColorManagementParams &cmp, float rawWhitePoint, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName); protected: - Glib::Mutex getImageMutex; // locks getImage + MyMutex getImageMutex; // locks getImage int W, H; ColorTemp wb; diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 329ad408e..a266d3747 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -30,6 +30,7 @@ #include "rawmetadatalocation.h" #include "iimage.h" #include "utils.h" +#include "../rtgui/threadutils.h" #include "settings.h" #include "LUT.h" /** @@ -417,7 +418,7 @@ namespace rtengine { void startBatchProcessing (ProcessingJob* job, BatchProcessingListener* bpl, bool tunnelMetaData); - extern Glib::Mutex* lcmsMutex; + extern MyMutex* lcmsMutex; } #endif diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 642126108..2968c76e7 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -18,6 +18,7 @@ */ #include "rtengine.h" #include "rtthumbnail.h" +#include "../rtgui/options.h" #include "image8.h" #include #include "curves.h" @@ -38,6 +39,8 @@ #include "jpeg.h" #include "../rtgui/ppversion.h" +extern Options options; + namespace rtengine { Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq) { @@ -1280,7 +1283,7 @@ bool Thumbnail::readData (const Glib::ustring& fname) { SafeKeyFile keyFile; try { - Glib::Mutex::Lock thmbLock(thumbMutex); + MyMutex::MyLock thmbLock(thumbMutex); if (!keyFile.load_from_file (fname)) return false; @@ -1309,7 +1312,14 @@ bool Thumbnail::readData (const Glib::ustring& fname) { } return true; } - catch (Glib::Error &err) {} + catch (Glib::Error &err) { + if (options.rtSettings.verbose) + printf("Thumbnail::readData / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str()); + } + catch (...) { + if (options.rtSettings.verbose) + printf("Thumbnail::readData / Unknown exception while trying to load \"%s\"!\n", fname.c_str()); + } return false; } @@ -1318,12 +1328,20 @@ bool Thumbnail::writeData (const Glib::ustring& fname) { SafeKeyFile keyFile; - Glib::Mutex::Lock thmbLock(thumbMutex); + MyMutex::MyLock thmbLock(thumbMutex); try { - if( safe_file_test(fname,Glib::FILE_TEST_EXISTS) ) - keyFile.load_from_file (fname); - } catch (...) {} + if( safe_file_test(fname,Glib::FILE_TEST_EXISTS) ) + keyFile.load_from_file (fname); + } + catch (Glib::Error &err) { + if (options.rtSettings.verbose) + printf("Thumbnail::writeData / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str()); + } + catch (...) { + if (options.rtSettings.verbose) + printf("Thumbnail::writeData / Unknown exception while trying to save \"%s\"!\n", fname.c_str()); + } keyFile.set_double ("LiveThumbData", "CamWBRed", camwbRed); keyFile.set_double ("LiveThumbData", "CamWBGreen", camwbGreen); @@ -1343,8 +1361,11 @@ bool Thumbnail::writeData (const Glib::ustring& fname) { keyFile.set_double_list ("LiveThumbData", "ColorMatrix", cm); FILE *f = safe_g_fopen (fname, "wt"); - if (!f) + if (!f) { + if (options.rtSettings.verbose) + printf("Thumbnail::writeData / Error: unable to open file \"\" with write access!\n", fname.c_str()); return false; + } else { fprintf (f, "%s", keyFile.to_data().c_str()); fclose (f); diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index f7037cf9d..fc0219d5f 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -26,12 +26,13 @@ #include "image8.h" #include "image16.h" #include "imagefloat.h" +#include "../rtgui/threadutils.h" namespace rtengine { class Thumbnail { - Glib::Mutex thumbMutex; + MyMutex thumbMutex; cmsHPROFILE camProfile; double iColorMatrix[3][3]; diff --git a/rtgui/batchqueue.h b/rtgui/batchqueue.h index e435407a8..68de4fbbf 100644 --- a/rtgui/batchqueue.h +++ b/rtgui/batchqueue.h @@ -19,6 +19,7 @@ #define _BATCHQUEUE_ #include +#include "threadutils.h" #include "batchqueueentry.h" #include "../rtengine/rtengine.h" #include "options.h" diff --git a/rtgui/batchqueueentry.cc b/rtgui/batchqueueentry.cc index 185632b9b..3728b3bd3 100644 --- a/rtgui/batchqueueentry.cc +++ b/rtgui/batchqueueentry.cc @@ -21,6 +21,7 @@ #include #include "guiutils.h" +#include "threadutils.h" #include "../rtengine/safegtk.h" #include "multilangmgr.h" diff --git a/rtgui/bqentryupdater.cc b/rtgui/bqentryupdater.cc index 8c806f850..61c430d52 100644 --- a/rtgui/bqentryupdater.cc +++ b/rtgui/bqentryupdater.cc @@ -33,7 +33,7 @@ void BatchQueueEntryUpdater::process (guint8* oimg, int ow, int oh, int newh, BQ } if (!qMutex) - qMutex = new Glib::Mutex (); + qMutex = new MyMutex (); qMutex->lock (); // look up if an older version is in the queue diff --git a/rtgui/bqentryupdater.h b/rtgui/bqentryupdater.h index 058486e09..f794e4cec 100644 --- a/rtgui/bqentryupdater.h +++ b/rtgui/bqentryupdater.h @@ -21,6 +21,7 @@ #include #include "../rtengine/rtengine.h" +#include "threadutils.h" #include "thumbnail.h" class BQEntryUpdateListener { @@ -45,7 +46,7 @@ class BatchQueueEntryUpdater { bool stopped; std::list jqueue; Glib::Thread* thread; - Glib::Mutex* qMutex; + MyMutex* qMutex; public: BatchQueueEntryUpdater (); diff --git a/rtgui/cacheimagedata.cc b/rtgui/cacheimagedata.cc index 61da6cf5e..2c6bfa338 100644 --- a/rtgui/cacheimagedata.cc +++ b/rtgui/cacheimagedata.cc @@ -36,73 +36,73 @@ int CacheImageData::load (const Glib::ustring& fname) { rtengine::SafeKeyFile keyFile; try { - bool loaded = keyFile.load_from_file (fname); - if (!loaded) { -#ifndef NDEBUG - printf("Failed to load_from_file(%s)\n", fname.c_str()); -#endif - return 1; - } + if (keyFile.load_from_file (fname)) { - if (keyFile.has_group ("General")) { - if (keyFile.has_key ("General", "MD5")) md5 = keyFile.get_string ("General", "MD5"); - if (keyFile.has_key ("General", "Version")) version = keyFile.get_string ("General", "Version"); - if (keyFile.has_key ("General", "Supported")) supported = keyFile.get_boolean ("General", "Supported"); - if (keyFile.has_key ("General", "Format")) format = (ThFileType)keyFile.get_integer ("General", "Format"); - if (keyFile.has_key ("General", "Rank")) rankOld = keyFile.get_integer ("General", "Rank"); - if (keyFile.has_key ("General", "InTrash")) inTrashOld = keyFile.get_boolean ("General", "InTrash"); - if (keyFile.has_key ("General", "RecentlySaved")) recentlySaved = keyFile.get_boolean ("General", "RecentlySaved"); - } - - timeValid = keyFile.has_group ("DateTime"); - - if (timeValid) { - if (keyFile.has_key ("DateTime", "Year")) year = keyFile.get_integer ("DateTime", "Year"); - if (keyFile.has_key ("DateTime", "Month")) month = keyFile.get_integer ("DateTime", "Month"); - if (keyFile.has_key ("DateTime", "Day")) day = keyFile.get_integer ("DateTime", "Day"); - if (keyFile.has_key ("DateTime", "Hour")) hour = keyFile.get_integer ("DateTime", "Hour"); - if (keyFile.has_key ("DateTime", "Min")) min = keyFile.get_integer ("DateTime", "Min"); - if (keyFile.has_key ("DateTime", "Sec")) sec = keyFile.get_integer ("DateTime", "Sec"); - if (keyFile.has_key ("DateTime", "MSec")) msec = keyFile.get_integer ("DateTime", "MSec"); - } - - exifValid = false; - - if (keyFile.has_group ("ExifInfo")) { - exifValid = true; - if (keyFile.has_key ("ExifInfo", "Valid")) exifValid = keyFile.get_boolean ("ExifInfo", "Valid"); - - if (exifValid) { - if (keyFile.has_key ("ExifInfo", "FNumber")) fnumber = keyFile.get_double ("ExifInfo", "FNumber"); - if (keyFile.has_key ("ExifInfo", "Shutter")) shutter = keyFile.get_double ("ExifInfo", "Shutter"); - if (keyFile.has_key ("ExifInfo", "FocalLen")) focalLen = keyFile.get_double ("ExifInfo", "FocalLen"); - if (keyFile.has_key ("ExifInfo", "FocalLen35mm")) focalLen35mm = keyFile.get_double ("ExifInfo", "FocalLen35mm"); - else focalLen35mm=focalLen; // prevent crashes on old files - if (keyFile.has_key ("ExifInfo", "FocusDist")) focusDist = keyFile.get_double ("ExifInfo", "FocusDist"); - else focusDist=0; - if (keyFile.has_key ("ExifInfo", "ISO")) iso = keyFile.get_integer ("ExifInfo", "ISO"); - if (keyFile.has_key ("ExifInfo", "ExpComp")) expcomp = keyFile.get_string ("ExifInfo", "ExpComp"); + if (keyFile.has_group ("General")) { + if (keyFile.has_key ("General", "MD5")) md5 = keyFile.get_string ("General", "MD5"); + if (keyFile.has_key ("General", "Version")) version = keyFile.get_string ("General", "Version"); + if (keyFile.has_key ("General", "Supported")) supported = keyFile.get_boolean ("General", "Supported"); + if (keyFile.has_key ("General", "Format")) format = (ThFileType)keyFile.get_integer ("General", "Format"); + if (keyFile.has_key ("General", "Rank")) rankOld = keyFile.get_integer ("General", "Rank"); + if (keyFile.has_key ("General", "InTrash")) inTrashOld = keyFile.get_boolean ("General", "InTrash"); + if (keyFile.has_key ("General", "RecentlySaved")) recentlySaved = keyFile.get_boolean ("General", "RecentlySaved"); } - if (keyFile.has_key ("ExifInfo", "Lens")) lens = keyFile.get_string ("ExifInfo", "Lens"); - if (keyFile.has_key ("ExifInfo", "Camera")) camera = keyFile.get_string ("ExifInfo", "Camera"); - } - if (keyFile.has_group ("FileInfo")) { - if (keyFile.has_key ("FileInfo", "Filetype")) filetype = keyFile.get_string ("FileInfo", "Filetype"); - } + timeValid = keyFile.has_group ("DateTime"); - if (format==FT_Raw && keyFile.has_group ("ExtraRawInfo")) { - if (keyFile.has_key ("ExtraRawInfo", "ThumbImageType")) thumbImgType = keyFile.get_integer ("ExtraRawInfo", "ThumbImageType"); - if (keyFile.has_key ("ExtraRawInfo", "ThumbImageOffset")) thumbOffset = keyFile.get_integer ("ExtraRawInfo", "ThumbImageOffset"); + if (timeValid) { + if (keyFile.has_key ("DateTime", "Year")) year = keyFile.get_integer ("DateTime", "Year"); + if (keyFile.has_key ("DateTime", "Month")) month = keyFile.get_integer ("DateTime", "Month"); + if (keyFile.has_key ("DateTime", "Day")) day = keyFile.get_integer ("DateTime", "Day"); + if (keyFile.has_key ("DateTime", "Hour")) hour = keyFile.get_integer ("DateTime", "Hour"); + if (keyFile.has_key ("DateTime", "Min")) min = keyFile.get_integer ("DateTime", "Min"); + if (keyFile.has_key ("DateTime", "Sec")) sec = keyFile.get_integer ("DateTime", "Sec"); + if (keyFile.has_key ("DateTime", "MSec")) msec = keyFile.get_integer ("DateTime", "MSec"); + } + + exifValid = false; + + if (keyFile.has_group ("ExifInfo")) { + exifValid = true; + if (keyFile.has_key ("ExifInfo", "Valid")) exifValid = keyFile.get_boolean ("ExifInfo", "Valid"); + + if (exifValid) { + if (keyFile.has_key ("ExifInfo", "FNumber")) fnumber = keyFile.get_double ("ExifInfo", "FNumber"); + if (keyFile.has_key ("ExifInfo", "Shutter")) shutter = keyFile.get_double ("ExifInfo", "Shutter"); + if (keyFile.has_key ("ExifInfo", "FocalLen")) focalLen = keyFile.get_double ("ExifInfo", "FocalLen"); + if (keyFile.has_key ("ExifInfo", "FocalLen35mm")) focalLen35mm = keyFile.get_double ("ExifInfo", "FocalLen35mm"); + else focalLen35mm=focalLen; // prevent crashes on old files + if (keyFile.has_key ("ExifInfo", "FocusDist")) focusDist = keyFile.get_double ("ExifInfo", "FocusDist"); + else focusDist=0; + if (keyFile.has_key ("ExifInfo", "ISO")) iso = keyFile.get_integer ("ExifInfo", "ISO"); + if (keyFile.has_key ("ExifInfo", "ExpComp")) expcomp = keyFile.get_string ("ExifInfo", "ExpComp"); + } + if (keyFile.has_key ("ExifInfo", "Lens")) lens = keyFile.get_string ("ExifInfo", "Lens"); + if (keyFile.has_key ("ExifInfo", "Camera")) camera = keyFile.get_string ("ExifInfo", "Camera"); + } + + if (keyFile.has_group ("FileInfo")) { + if (keyFile.has_key ("FileInfo", "Filetype")) filetype = keyFile.get_string ("FileInfo", "Filetype"); + } + + if (format==FT_Raw && keyFile.has_group ("ExtraRawInfo")) { + if (keyFile.has_key ("ExtraRawInfo", "ThumbImageType")) thumbImgType = keyFile.get_integer ("ExtraRawInfo", "ThumbImageType"); + if (keyFile.has_key ("ExtraRawInfo", "ThumbImageOffset")) thumbOffset = keyFile.get_integer ("ExtraRawInfo", "ThumbImageOffset"); + } + else { + rotate = 0; + thumbImgType = 0; + } + return 0; } - else { - rotate = 0; - thumbImgType = 0; - } - return 0; } catch (Glib::Error &err) { - printf("Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str()); + if (options.rtSettings.verbose) + printf("CacheImageData::load / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str()); + } + catch (...) { + if (options.rtSettings.verbose) + printf("CacheImageData::load / Unknown exception while trying to load \"%s\"!\n", fname.c_str()); } return 1; } @@ -114,7 +114,19 @@ int CacheImageData::save (const Glib::ustring& fname) { rtengine::SafeKeyFile keyFile; - if (safe_file_test(fname,Glib::FILE_TEST_EXISTS)) keyFile.load_from_file (fname); + if (safe_file_test(fname,Glib::FILE_TEST_EXISTS)) { + try { + keyFile.load_from_file (fname); + } + catch (Glib::Error &err) { + if (options.rtSettings.verbose) + printf("CacheImageData::save / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str()); + } + catch (...) { + if (options.rtSettings.verbose) + printf("CacheImageData::save / Unknown exception while trying to save \"%s\"!\n", fname.c_str()); + } + } keyFile.set_string ("General", "MD5", md5); keyFile.set_string ("General", "Version", VERSION); // Application's version @@ -126,7 +138,7 @@ int CacheImageData::save (const Glib::ustring& fname) { if (keyFile.has_key ("General", "Rank")) keyFile.remove_key("General", "Rank"); if (keyFile.has_key ("General", "InTrash")) keyFile.remove_key("General", "InTrash"); - if (timeValid) { + if (timeValid) { keyFile.set_integer ("DateTime", "Year", year); keyFile.set_integer ("DateTime", "Month", month); keyFile.set_integer ("DateTime", "Day", day); @@ -137,7 +149,7 @@ int CacheImageData::save (const Glib::ustring& fname) { } keyFile.set_boolean ("ExifInfo", "Valid", exifValid); - if (exifValid) { + if (exifValid) { keyFile.set_double ("ExifInfo", "FNumber", fnumber); keyFile.set_double ("ExifInfo", "Shutter", shutter); keyFile.set_double ("ExifInfo", "FocalLen", focalLen); @@ -156,8 +168,11 @@ int CacheImageData::save (const Glib::ustring& fname) { } FILE *f = safe_g_fopen (fname, "wt"); - if (!f) + if (!f) { + if (options.rtSettings.verbose) + printf("CacheImageData::save / Error: unable to open file \"\" with write access!\n", fname.c_str()); return 1; + } else { fprintf (f, "%s", keyFile.to_data().c_str()); fclose (f); diff --git a/rtgui/cachemanager.cc b/rtgui/cachemanager.cc index c392f6f04..5296dd9a8 100644 --- a/rtgui/cachemanager.cc +++ b/rtgui/cachemanager.cc @@ -33,8 +33,8 @@ CacheManager::getInstance(void) static CacheManager* instance_ = 0; if ( instance_ == 0 ) { - static Glib::Mutex smutex_; - Glib::Mutex::Lock lock(smutex_); + static MyMutex smutex_; + MyMutex::MyLock lock(smutex_); if ( instance_ == 0 ) { instance_ = new CacheManager(); @@ -45,7 +45,7 @@ CacheManager::getInstance(void) void CacheManager::init () { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); openEntries.clear (); baseDir = options.cacheBaseDir; @@ -75,7 +75,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname, const rtengine::p // take manager lock and search for entry, if found return it else release // lock and create it { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); string_thumb_map::iterator r = openEntries.find (fname); // if it is open, return it @@ -119,7 +119,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname, const rtengine::p // was use it over our version. if not added we create the cache entry if (res) { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); string_thumb_map::iterator r = openEntries.find (fname); if (r!=openEntries.end()) { @@ -138,7 +138,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname, const rtengine::p void CacheManager::deleteEntry (const Glib::ustring& fname) { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); // check if it is opened string_thumb_map::iterator r = openEntries.find (fname); @@ -200,7 +200,7 @@ void CacheManager::clearFromCache (const Glib::ustring& fname, bool leavenotrace void CacheManager::renameEntry (const std::string& oldfilename, const std::string& oldmd5, const std::string& newfilename) { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); std::string newmd5 = getMD5 (newfilename); @@ -228,7 +228,7 @@ void CacheManager::renameEntry (const std::string& oldfilename, const std::strin void CacheManager::closeThumbnail (Thumbnail* t) { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); t->updateCache (); string_thumb_map::iterator r = openEntries.find (t->getFileName()); @@ -239,14 +239,14 @@ void CacheManager::closeThumbnail (Thumbnail* t) { void CacheManager::closeCache () { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); applyCacheSizeLimitation (); } void CacheManager::clearAll () { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); deleteDir ("images"); deleteDir ("aehistograms"); @@ -264,7 +264,7 @@ void CacheManager::clearAll () { } void CacheManager::clearThumbImages () { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); deleteDir ("images"); deleteDir ("aehistograms"); @@ -272,7 +272,7 @@ void CacheManager::clearThumbImages () { } void CacheManager::clearProfiles () { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); deleteDir ("profiles"); } diff --git a/rtgui/cachemanager.h b/rtgui/cachemanager.h index a592b8f07..183d304f7 100644 --- a/rtgui/cachemanager.h +++ b/rtgui/cachemanager.h @@ -25,6 +25,7 @@ #include "thumbnail.h" #include #include "../rtengine/procparams.h" +#include "threadutils.h" class Thumbnail; @@ -35,7 +36,7 @@ class CacheManager { string_thumb_map openEntries; Glib::ustring baseDir; - Glib::Mutex mutex_; + MyMutex mutex_; void deleteDir (const Glib::ustring& dirName); @@ -43,20 +44,20 @@ class CacheManager { public: - static CacheManager* getInstance(void); + static CacheManager* getInstance(void); void init (); Thumbnail* getEntry (const Glib::ustring& fname, const rtengine::procparams::ProcParams *pparams=NULL); void deleteEntry (const Glib::ustring& fname); void renameEntry (const std::string& oldfilename, const std::string& oldmd5, const std::string& newfilename); - + void closeThumbnail (Thumbnail* t); - - const Glib::ustring& getBaseDir () { Glib::Mutex::Lock lock(mutex_); return baseDir; } + + const Glib::ustring& getBaseDir () { MyMutex::MyLock lock(mutex_); return baseDir; } void closeCache (); static std::string getMD5 (const Glib::ustring& fname); - + void clearAll (); void clearThumbImages (); void clearProfiles (); diff --git a/rtgui/crophandler.h b/rtgui/crophandler.h index d9dd4dd7d..cd0c7406d 100644 --- a/rtgui/crophandler.h +++ b/rtgui/crophandler.h @@ -20,6 +20,7 @@ #define __CROPHANDLER__ #include "../rtengine/rtengine.h" +#include "threadutils.h" #include class CropHandlerListener { @@ -48,7 +49,7 @@ class CropHandler : public rtengine::DetailedCropListener, public rtengine::Size int cropX, cropY, cropW, cropH; // position and size of the crop corresponding to cropPixbuf bool enabled; unsigned char* cropimg; - unsigned char* cropimgtrue; + unsigned char* cropimgtrue; int cropimg_width, cropimg_height, cix, ciy, ciw, cih, cis; bool initial; bool isLowUpdatePriority; @@ -60,24 +61,24 @@ class CropHandler : public rtengine::DetailedCropListener, public rtengine::Size CropHandlerIdleHelper* chi; void compDim (); - + public: - void update (); + void update (); rtengine::procparams::CropParams cropParams; - rtengine::procparams::ColorManagementParams colorParams; + rtengine::procparams::ColorManagementParams colorParams; Glib::RefPtr cropPixbuf; - Glib::RefPtr cropPixbuftrue; + Glib::RefPtr cropPixbuftrue; - Glib::Mutex cimg; + MyMutex cimg; CropHandler (); ~CropHandler (); - + void setCropHandlerListener (CropHandlerListener* l) { listener = l; } - + void newImage (rtengine::StagedImageProcessor* ipc_); void setZoom (int z, int centerx=-1, int centery=-1); double getFitZoom (); @@ -93,11 +94,11 @@ class CropHandler : public rtengine::DetailedCropListener, public rtengine::Size // DetailedCropListener interface void setDetailedCrop (rtengine::IImage8* im, rtengine::IImage8* imworking,rtengine::procparams::ColorManagementParams cmp, - rtengine::procparams::CropParams cp, int cx, int cy, int cw, int ch, int skip); + rtengine::procparams::CropParams cp, int cx, int cy, int cw, int ch, int skip); bool getWindow (int& cwx, int& cwy, int& cww, int& cwh, int& cskip); // SizeListener interface void sizeChanged (int w, int h, int ow, int oh); - + void cutRectToImgBounds (int& x, int& y, int& w, int& h); }; diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index fe2f75358..1c227bb66 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -21,6 +21,7 @@ #include "cropwindow.h" #include "options.h" #include "guiutils.h" +#include "threadutils.h" #include "../rtengine/mytime.h" #include "imagearea.h" #include "cursormanager.h" @@ -488,7 +489,7 @@ void CropWindow::pointerMoved (int x, int y) { if (pmhlistener) pmhlistener->pointerMoved (false, cropHandler.colorParams.working, mx, my, -1, -1, -1); } else { - /*Glib::Mutex::Lock lock(cropHandler.cimg); + /*MyMutex::MyLock lock(cropHandler.cimg); int vx = x - xpos - imgX; int vy = y - ypos - imgY; @@ -630,7 +631,7 @@ void CropWindow::updateCursor (int x, int y) { } void CropWindow::expose (Cairo::RefPtr cr) { - Glib::Mutex::Lock lock(cropHandler.cimg); + MyMutex::MyLock lock(cropHandler.cimg); //MyTime t1, t2, t3, t4; diff --git a/rtgui/editwindow.cc b/rtgui/editwindow.cc index f97960c7b..6a67e2b51 100644 --- a/rtgui/editwindow.cc +++ b/rtgui/editwindow.cc @@ -22,6 +22,7 @@ #include "rtwindow.h" #include #include "rtimage.h" +#include "threadutils.h" static EditWindow* editWnd = NULL; @@ -36,16 +37,16 @@ EditWindow* EditWindow::getInstance(RTWindow* p) if ( editWnd == NULL ) { - static Glib::Mutex smutex_; - Glib::Mutex::Lock lock(smutex_); + static MyMutex smutex_; + MyMutex::MyLock lock(smutex_); if ( editWnd == 0 ) { editWnd = new EditWindow(p); // Determine the other display and maximize the window on that - const Glib::RefPtr< Gdk::Window >& wnd=p->get_window(); + const Glib::RefPtr< Gdk::Window >& wnd=p->get_window(); int monNo=p->get_screen()->get_monitor_at_window (wnd); - + Gdk::Rectangle lMonitorRect; editWnd->get_screen()->get_monitor_geometry(monNo==0 ? 1:0, lMonitorRect); editWnd->move(lMonitorRect.get_x(), lMonitorRect.get_y()); diff --git a/rtgui/extprog.cc b/rtgui/extprog.cc index 642375e75..f399b0b0f 100644 --- a/rtgui/extprog.cc +++ b/rtgui/extprog.cc @@ -68,8 +68,8 @@ ExtProgStore* ExtProgStore::getInstance() static ExtProgStore* instance_ = 0; if ( instance_ == 0 ) { - static Glib::Mutex smutex_; - Glib::Mutex::Lock lock(smutex_); + static MyMutex smutex_; + MyMutex::MyLock lock(smutex_); if ( instance_ == 0 ) { instance_ = new ExtProgStore(); @@ -84,7 +84,7 @@ ExtProgStore::~ExtProgStore() { // Reads all profiles from the given profiles dir void ExtProgStore::init () { - Glib::Mutex::Lock lock(mtx); + MyMutex::MyLock lock(mtx); lActions.clear(); diff --git a/rtgui/extprog.h b/rtgui/extprog.h index c5586c592..6401cc09f 100644 --- a/rtgui/extprog.h +++ b/rtgui/extprog.h @@ -22,6 +22,7 @@ #include #include +#include "threadutils.h" class ExtProgAction { public: @@ -40,7 +41,7 @@ public: // Stores all external programs that could be called by the user class ExtProgStore { - Glib::Mutex mtx; // covers actions + MyMutex mtx; // covers actions bool SearchProg(Glib::ustring name, Glib::ustring exePath, Glib::ustring exePath86, int maxVer, bool allowRaw, bool allowQueueProcess); diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 8899fb4dc..1a4c41a5a 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -29,7 +29,7 @@ #include "../rtengine/dfmanager.h" #include "../rtengine/ffmanager.h" #include "rtimage.h" -#include "guiutils.h" +#include "threadutils.h" extern Options options; diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index b9091bbe2..557c452aa 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -21,6 +21,7 @@ #include "cursormanager.h" #include #include "guiutils.h" +#include "threadutils.h" #include "../rtengine/safegtk.h" #include diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 89f71ba0a..ae6bcd44f 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -463,7 +463,7 @@ void FileCatalog::closeDir () { fileNameList.clear (); { - Glib::Mutex::Lock lock(dirEFSMutex); + MyMutex::MyLock lock(dirEFSMutex); dirEFS.clear (); } hasValidCurrentEFS = false; @@ -588,7 +588,7 @@ void FileCatalog::previewReady (int dir_id, FileBrowserEntry* fdn) { const CacheImageData* cfs = fdn->thumbnail->getCacheImageData(); { - Glib::Mutex::Lock lock(dirEFSMutex); + MyMutex::MyLock lock(dirEFSMutex); if (cfs->exifValid) { if (cfs->fnumber < dirEFS.fnumberFrom) dirEFS.fnumberFrom = cfs->fnumber; @@ -634,7 +634,7 @@ void FileCatalog::previewsFinishedUI () { if (filterPanel) { filterPanel->set_sensitive (true); if ( !hasValidCurrentEFS ){ - Glib::Mutex::Lock lock(dirEFSMutex); + MyMutex::MyLock lock(dirEFSMutex); currentEFS = dirEFS; filterPanel->setFilter ( dirEFS,true ); }else { @@ -672,7 +672,7 @@ void FileCatalog::previewsFinished (int dir_id) { } if (!hasValidCurrentEFS) { - Glib::Mutex::Lock lock(dirEFSMutex); + MyMutex::MyLock lock(dirEFSMutex); currentEFS = dirEFS; } @@ -1322,7 +1322,7 @@ BrowserFilter FileCatalog::getFilter () { filter.exifFilterEnabled = false; else { if (!hasValidCurrentEFS) { - Glib::Mutex::Lock lock(dirEFSMutex); + MyMutex::MyLock lock(dirEFSMutex); filter.exifFilter = dirEFS; } else diff --git a/rtgui/filecatalog.h b/rtgui/filecatalog.h index 410371253..37dfdfaf6 100644 --- a/rtgui/filecatalog.h +++ b/rtgui/filecatalog.h @@ -36,6 +36,7 @@ #include "exportpanel.h" #include "previewloader.h" #include "multilangmgr.h" +#include "threadutils.h" class DirEntry { @@ -133,7 +134,7 @@ class FileCatalog : public Gtk::VBox, Gtk::Button* zoomInButton; Gtk::Button* zoomOutButton; - Glib::Mutex dirEFSMutex; + MyMutex dirEFSMutex; ExifFilterSettings dirEFS; ExifFilterSettings currentEFS; bool hasValidCurrentEFS; diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 7d9214f31..6ffdc601f 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -20,7 +20,6 @@ #define __GUI_UTILS_ #include -#include #include "../rtengine/rtengine.h" #include #include @@ -77,455 +76,6 @@ public: } }; -#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 -//#define TRACE_MYRWMUTEX 1 - - -/** - * @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::Mutex handlerMutex; - Glib::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 - - { - // to operate safely - 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; - #if TRACE_MYRWMUTEX - rwMutex.lastWriterFile = file; - rwMutex.lastWriterLine = line; - rwMutex.ownerThread = thread; - std::cout << thread << "/" << locknumber << ":" << name << " / " << file << " : " << line << " - locking - R ++ 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 - // 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 - 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; - #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 - 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; - } - #if TRACE_MYRWMUTEX - else std::cout << thread << "/" << locknumber << " / already unlocked - R (release)" << std::endl; - #endif - } -}; - -/** - * @brief Custom WriterLock with debugging feature, to replace the buggy Glib::RWLock (can have negative reader_count value!) - * - */ -class MyWriterLock { - - MyRWMutex& rwMutex; - bool locked; - - #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 - 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 - 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) { - // to operate safely - 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 - 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) { - // to operate safely - 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 - std::cout << " <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl; - #endif - - rwMutex.handlerMutex.unlock(); - - locked = false; - } - #if TRACE_MYRWMUTEX - else std::cout << thread << "/" << locknumber << " / already unlocked by this object - W (release)" << std::endl; - #endif - } -}; - -#if TRACE_MYRWMUTEX -#define MYREADERLOCK(ln, e) MyReaderLock ln(e, #e, __FILE__, __LINE__); -#define MYWRITERLOCK(ln, e) MyWriterLock ln(e, #e, __FILE__, __LINE__); -#define MYREADERLOCK_ACQUIRE(ln) ln.acquire(__FILE__, __LINE__); -#define MYWRITERLOCK_ACQUIRE(ln) ln.acquire(__FILE__, __LINE__); -#define MYREADERLOCK_RELEASE(ln) ln.release(__FILE__, __LINE__); -#define MYWRITERLOCK_RELEASE(ln) ln.release(__FILE__, __LINE__); -#else -#define MYREADERLOCK(ln, e) MyReaderLock ln(e); -#define MYWRITERLOCK(ln, e) MyWriterLock ln(e); -#define MYREADERLOCK_ACQUIRE(ln) ln.acquire(); -#define MYWRITERLOCK_ACQUIRE(ln) ln.acquire(); -#define MYREADERLOCK_RELEASE(ln) ln.release(); -#define MYWRITERLOCK_RELEASE(ln) ln.release(); -#endif - /** * @brief subclass of Gtk::ScrolledWindow in order to handle the scrollwheel */ diff --git a/rtgui/main.cc b/rtgui/main.cc index 86cee803b..3aa5e2a89 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -90,6 +90,12 @@ int processLineParams( int argc, char **argv ); int main(int argc, char **argv) { setlocale(LC_ALL,""); + + Glib::thread_init(); + gdk_threads_set_lock_functions(G_CALLBACK(myGdkLockEnter), (G_CALLBACK(myGdkLockLeave))); + gdk_threads_init(); + Gio::init (); + #ifdef BUILD_BUNDLE char exname[512] = {0}; Glib::ustring exePath; @@ -127,11 +133,6 @@ int main(int argc, char **argv) licensePath = LICENCE_SEARCH_PATH; #endif - Glib::thread_init(); - gdk_threads_set_lock_functions(G_CALLBACK(myGdkLockEnter), (G_CALLBACK(myGdkLockLeave))); - gdk_threads_init(); - Gio::init (); - mainThread = Glib::Thread::self(); Options::load (); diff --git a/rtgui/options.cc b/rtgui/options.cc index ae64f0fb6..521d52c4b 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -499,22 +499,20 @@ int Options::readFromFile (Glib::ustring fname) { rtengine::SafeKeyFile keyFile; - try { - if( !safe_file_test(fname,Glib::FILE_TEST_EXISTS)) - return 1; - if (!keyFile.load_from_file (fname)) - return 1; - } - catch (Glib::FileError &err) { + if( !safe_file_test(fname,Glib::FILE_TEST_EXISTS)) return 1; - } - setDefaults (); + try { + if (keyFile.load_from_file (fname)) { + + setDefaults (); +// -------------------------------------------------------------------------------------------------------- + if (keyFile.has_group ("General")) { if (keyFile.has_key ("General", "TabbedEditor")) tabbedUI= keyFile.get_boolean ("General", "TabbedEditor"); if (keyFile.has_key ("General", "StartupDirectory")){ - if( keyFile.get_string ("General", "StartupDirectory") == "home") startupDir = STARTUPDIR_HOME; + if ( keyFile.get_string ("General", "StartupDirectory") == "home") startupDir = STARTUPDIR_HOME; else if ( keyFile.get_string ("General", "StartupDirectory") == "current") startupDir = STARTUPDIR_CURRENT; else if ( keyFile.get_string ("General", "StartupDirectory") == "last") startupDir = STARTUPDIR_LAST; else if ( keyFile.get_string ("General", "StartupDirectory") == "custom") startupDir = STARTUPDIR_CUSTOM; @@ -669,8 +667,6 @@ if (keyFile.has_group ("GUI")) { if (keyFile.has_key ("GUI", "UseIconNoText")) UseIconNoText = keyFile.get_boolean ("GUI", "UseIconNoText"); } - - if (keyFile.has_group ("Crop Settings")) { if (keyFile.has_key ("Crop Settings", "PPI")) cropPPI = keyFile.get_integer ("Crop Settings", "PPI"); } @@ -703,7 +699,7 @@ if (keyFile.has_group ("Color Management")) { if( keyFile.has_key ("Color Management", "ProtectRed")) rtSettings.protectred = keyFile.get_integer("Color Management", "ProtectRed"); if( keyFile.has_key ("Color Management", "ProtectRedH")) rtSettings.protectredh = keyFile.get_double("Color Management", "ProtectRedH"); // if( keyFile.has_key ("Color Management", "Ciebadpixgauss")) rtSettings.ciebadpixgauss = keyFile.get_boolean("Color Management", "Ciebadpixgauss"); - + } if (keyFile.has_group ("Batch Processing")) { @@ -764,9 +760,25 @@ if (keyFile.has_group ("Dialogs")) { safeDirGet(keyFile, "Dialogs", "LastProfilingReferenceDir", lastProfilingReferenceDir); } - filterOutParsedExtensions (); +// -------------------------------------------------------------------------------------------------------- + + filterOutParsedExtensions (); + + return 0; + + } + } + catch (Glib::Error &err) { + if (options.rtSettings.verbose) + printf("Options::readFromFile / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str()); + } + catch (...) { + if (options.rtSettings.verbose) + printf("Options::readFromFile / Unknown exception while trying to load \"%s\"!\n", fname.c_str()); + } + + return 1; - return 0; } bool Options::safeDirGet(const rtengine::SafeKeyFile& keyFile, const Glib::ustring& section, @@ -1015,8 +1027,11 @@ int Options::saveToFile (Glib::ustring fname) { keyFile.set_string ("Dialogs", "LastProfilingReferenceDir", lastProfilingReferenceDir); FILE *f = safe_g_fopen (fname, "wt"); - if (f==NULL) + if (f==NULL) { + if (options.rtSettings.verbose) + printf("Options::saveToFile / Error: unable to open file \"\" with write access!\n", fname.c_str()); return 1; + } else { fprintf (f, "%s", keyFile.to_data().c_str()); fclose (f); diff --git a/rtgui/previewhandler.cc b/rtgui/previewhandler.cc index 6f409efde..68828cf5d 100644 --- a/rtgui/previewhandler.cc +++ b/rtgui/previewhandler.cc @@ -168,11 +168,11 @@ void PreviewHandler::imageReady (CropParams cp) { iaimgpar* iap = new iaimgpar; iap->pih = pih; iap->cp = cp; - g_idle_add (imageReadyUI, iap); + g_idle_add (imageReadyUI, iap); } Glib::RefPtr PreviewHandler::getRoughImage (int x, int y, int w, int h, double zoom) { - Glib::Mutex::Lock lock(previewImgMutex); + MyMutex::MyLock lock(previewImgMutex); Glib::RefPtr resPixbuf; @@ -201,7 +201,7 @@ Glib::RefPtr PreviewHandler::getRoughImage (int x, int y, int w, in } Glib::RefPtr PreviewHandler::getRoughImage (int desiredW, int desiredH, double& zoom_) { - Glib::Mutex::Lock lock(previewImgMutex); + MyMutex::MyLock lock(previewImgMutex); Glib::RefPtr resPixbuf; diff --git a/rtgui/previewhandler.h b/rtgui/previewhandler.h index c51a2c4ef..8eaa0b3d7 100644 --- a/rtgui/previewhandler.h +++ b/rtgui/previewhandler.h @@ -20,6 +20,7 @@ #define _PREVIEWHANDLER_ #include "../rtengine/rtengine.h" +#include "threadutils.h" #include #include @@ -49,10 +50,9 @@ class PreviewHandler : public rtengine::PreviewImageListener { double previewScale; PreviewHandlerIdleHelper* pih; std::list listeners; - Glib::Mutex previewImgMutex; + MyMutex previewImgMutex; Glib::RefPtr previewImg; - - + public: PreviewHandler (); diff --git a/rtgui/previewloader.cc b/rtgui/previewloader.cc index 63e530361..3a1d2ea6b 100644 --- a/rtgui/previewloader.cc +++ b/rtgui/previewloader.cc @@ -20,6 +20,7 @@ #include #include "previewloader.h" #include "guiutils.h" +#include "threadutils.h" #include "../rtengine/safegtk.h" #ifdef _OPENMP @@ -75,7 +76,7 @@ public: } Glib::ThreadPool* threadPool_; - Glib::Mutex mutex_; + MyMutex mutex_; JobSet jobs_; gint nConcurrentThreads; @@ -83,7 +84,7 @@ public: { Job j; { - Glib::Mutex::Lock lock(mutex_); + MyMutex::MyLock lock(mutex_); // nothing to do; could be jobs have been removed if ( jobs_.empty() ) @@ -137,8 +138,8 @@ PreviewLoader* PreviewLoader::getInstance(void) static PreviewLoader* instance_ = NULL; if ( instance_ == NULL ) { - static Glib::Mutex smutex_; - Glib::Mutex::Lock lock(smutex_); + static MyMutex smutex_; + MyMutex::MyLock lock(smutex_); if ( instance_ == NULL ) instance_ = new PreviewLoader(); } @@ -152,7 +153,7 @@ void PreviewLoader::add(int dir_id, const Glib::ustring& dir_entry, PreviewLoade if ( l != 0 ) { { - Glib::Mutex::Lock lock(impl_->mutex_); + MyMutex::MyLock lock(impl_->mutex_); // create a new job and append to queue DEBUG("saving job %s",dir_entry.c_str()); @@ -168,7 +169,7 @@ void PreviewLoader::add(int dir_id, const Glib::ustring& dir_entry, PreviewLoade void PreviewLoader::removeAllJobs(void) { DEBUG("stop %d",impl_->nConcurrentThreads); - Glib::Mutex::Lock lock(impl_->mutex_); + MyMutex::MyLock lock(impl_->mutex_); impl_->jobs_.clear(); } diff --git a/rtgui/profilestore.cc b/rtgui/profilestore.cc index 7d8b5f8b1..13026b663 100644 --- a/rtgui/profilestore.cc +++ b/rtgui/profilestore.cc @@ -36,7 +36,7 @@ bool ProfileStore::init () { return false; if (storeState == STORESTATE_NOTINITIALIZED) { storeState = STORESTATE_BEINGINITIALIZED; - parseMutex = new Glib::Mutex(); + parseMutex = new MyMutex(); _parseProfiles (); storeState = STORESTATE_INITIALIZED; } @@ -47,7 +47,7 @@ ProfileStore::~ProfileStore () { // This lock prevent object's suppression while scanning the directories storeState = STORESTATE_DELETED; - Glib::Mutex::Lock lock(*parseMutex); + MyMutex::MyLock lock(*parseMutex); for (std::map::iterator i = partProfiles.begin(); i!=partProfiles.end(); i++) { if (i->second->pparams) delete i->second->pparams; @@ -71,7 +71,7 @@ void ProfileStore::parseProfiles () { if (!init()) // I don't even know if this situation can occur return; - Glib::Mutex::Lock lock(*parseMutex); + MyMutex::MyLock lock(*parseMutex); _parseProfiles (); } @@ -148,7 +148,7 @@ const PartialProfile* ProfileStore::getProfile (const Glib::ustring& profname) { if (!init()) // I don't even know if this situation can occur return NULL; - Glib::Mutex::Lock lock(*parseMutex); + MyMutex::MyLock lock(*parseMutex); if (partProfiles.find(profname) != partProfiles.end()) { return partProfiles[profname]; @@ -165,7 +165,7 @@ std::vector ProfileStore::getProfileNames () { if (!init()) // I don't even know if this situation can occur return ret; - Glib::Mutex::Lock lock(*parseMutex); + MyMutex::MyLock lock(*parseMutex); for (std::map::iterator i = partProfiles.begin(); i!=partProfiles.end(); i++) ret.push_back (i->first); diff --git a/rtgui/profilestore.h b/rtgui/profilestore.h index a58c51da5..c90037fb1 100644 --- a/rtgui/profilestore.h +++ b/rtgui/profilestore.h @@ -22,6 +22,7 @@ #include #include #include "../rtengine/rtengine.h" +#include "threadutils.h" #include "paramsedited.h" #include @@ -34,7 +35,7 @@ class ProfileStore { STORESTATE_DELETED } StoreState; - Glib::Mutex *parseMutex; + MyMutex *parseMutex; StoreState storeState; std::map partProfiles; void parseDir (const Glib::ustring& pdir); diff --git a/rtgui/rtimage.cc b/rtgui/rtimage.cc index 80bd00cb1..f90eb397a 100644 --- a/rtgui/rtimage.cc +++ b/rtgui/rtimage.cc @@ -100,13 +100,23 @@ void RTImage::setPaths(Options &opt) { else { configFilename = Glib::build_filename(argv0, Glib::build_filename("themes", Glib::ustring::format(opt.theme, ".iconset"))); } - if (!safe_file_test(configFilename, Glib::FILE_TEST_EXISTS) || !keyFile.load_from_file (configFilename)) { - // ...otherwise fallback to the iconset set in default.iconset - configFilename = Glib::build_filename(argv0, Glib::build_filename("themes", "Default.iconset")); - if (!keyFile.load_from_file (configFilename)) { - hasKeyFile = false; + try { + if (!safe_file_test(configFilename, Glib::FILE_TEST_EXISTS) || !keyFile.load_from_file (configFilename)) { + // ...otherwise fallback to the iconset set in default.iconset + configFilename = Glib::build_filename(argv0, Glib::build_filename("themes", "Default.iconset")); + if (!keyFile.load_from_file (configFilename)) { + hasKeyFile = false; + } } } + catch (Glib::Error &err) { + if (options.rtSettings.verbose) + printf("RTImage::setPaths / Error code %d while reading values from \"%s\":\n%s\n", err.code(), configFilename.c_str(), err.what().c_str()); + } + catch (...) { + if (options.rtSettings.verbose) + printf("RTImage::setPaths / Unknown exception while trying to load \"%s\"!\n", configFilename.c_str()); + } if (hasKeyFile && keyFile.has_group ("General")) { Glib::ustring iSet; diff --git a/rtgui/threadutils.h b/rtgui/threadutils.h new file mode 100644 index 000000000..907d521e0 --- /dev/null +++ b/rtgui/threadutils.h @@ -0,0 +1,619 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * 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 . + */ + + +#ifndef _THREADUTILS_ +#define _THREADUTILS_ + +#include +#include // for raise() +#include + +#ifdef WIN32 +#include +#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 +//#define TRACE_MYRWMUTEX 1 +//#undef STRICT_MUTEX +//#define STRICT_MUTEX 1 + +/** + * @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::RecMutex (STRICT_MUTEX=0) or a Glib::Threads::Mutex (STRICT_MUTEX=1), but in this case, the application will + * crash instead of freezing. + * + * In Debug builds, a printf will let you know that the MyMutex was already locked + * + * The default and recommended mode is STRICT_MUTEX=1 + */ + +#ifdef WIN32 +class MyMutex : public Glib::RecMutex { +#else +class MyMutex : public Glib::Threads::RecMutex { +#endif + +#if STRICT_MUTEX || !defined(NDEBUG) +private: + bool alreadyLocked; +#endif + +public: + class MyLock; + +#if STRICT_MUTEX || !defined(NDEBUG) + MyMutex() : alreadyLocked(false) {} +#else + MyMutex() {} +#endif + + void lock() { + #ifdef WIN32 + Glib::RecMutex::lock(); + #else + Glib::Threads::RecMutex::lock(); + #endif + #if STRICT_MUTEX || !defined(NDEBUG) + if (alreadyLocked) { + #ifndef NDEBUG + printf("Warning: MyMutex already locked!\n"); // breakpoint + #endif + #if STRICT_MUTEX + #ifndef NDEBUG + #ifdef WIN32 + DebugBreak(); + #else + raise(SIGTRAP); + #endif + #else + raise(SIGINT); + #endif + #endif + } + alreadyLocked = true; + #endif + } + + bool trylock() { + #ifdef WIN32 + if (Glib::RecMutex::trylock()) + #else + if (Glib::Threads::RecMutex::trylock()) + #endif + { + #if STRICT_MUTEX || !defined(NDEBUG) + if (alreadyLocked) { + #ifndef NDEBUG + printf("Warning: MyMutex already locked!\n"); // breakpoint + #endif + #if STRICT_MUTEX + #ifndef NDEBUG + #ifdef WIN32 + DebugBreak(); + #else + raise(SIGTRAP); + #endif + #else + raise(SIGINT); + #endif + #endif + } + alreadyLocked = true; + #endif + return true; + } + return false; + } + + // Warning: the base class of MyMutex is RecMutex, but the mutex is said "unlocked" on first occurrence of "unlock", to avoid overhead. + void unlock() { + #if STRICT_MUTEX || !defined(NDEBUG) + alreadyLocked = false; + #endif + #ifdef WIN32 + Glib::RecMutex::unlock(); + #else + Glib::Threads::RecMutex::unlock(); + #endif + } +}; + + +// 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: +#ifdef WIN32 + Glib::Mutex handlerMutex; // Having a recursive or non-recursive mutex is not important here, so we can use Glib::Mutex + Glib::Cond access; +#else + 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; +#endif + 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 + + { + // to operate safely + 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; + #if TRACE_MYRWMUTEX + rwMutex.lastWriterFile = file; + rwMutex.lastWriterLine = line; + rwMutex.ownerThread = thread; + std::cout << thread << "/" << locknumber << ":" << name << " / " << file << " : " << line << " - locking - R ++ 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 + // 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 - 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; + #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 + 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; + } + #if TRACE_MYRWMUTEX + else std::cout << thread << "/" << locknumber << " / already unlocked - R (release)" << std::endl; + #endif + } +}; + +/** + * @brief Custom WriterLock with debugging feature, to replace the buggy Glib::RWLock (can have negative reader_count value!) + * + */ +class MyWriterLock { + + MyRWMutex& rwMutex; + bool locked; + + #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 + 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 + 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) { + // to operate safely + 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 + 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) { + // to operate safely + 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 + std::cout << " <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl; + #endif + + rwMutex.handlerMutex.unlock(); + + locked = false; + } + #if TRACE_MYRWMUTEX + else std::cout << thread << "/" << locknumber << " / already unlocked by this object - W (release)" << std::endl; + #endif + } +}; + +#if TRACE_MYRWMUTEX +#define MYREADERLOCK(ln, e) MyReaderLock ln(e, #e, __FILE__, __LINE__); +#define MYWRITERLOCK(ln, e) MyWriterLock ln(e, #e, __FILE__, __LINE__); +#define MYREADERLOCK_ACQUIRE(ln) ln.acquire(__FILE__, __LINE__); +#define MYWRITERLOCK_ACQUIRE(ln) ln.acquire(__FILE__, __LINE__); +#define MYREADERLOCK_RELEASE(ln) ln.release(__FILE__, __LINE__); +#define MYWRITERLOCK_RELEASE(ln) ln.release(__FILE__, __LINE__); +#else +#define MYREADERLOCK(ln, e) MyReaderLock ln(e); +#define MYWRITERLOCK(ln, e) MyWriterLock ln(e); +#define MYREADERLOCK_ACQUIRE(ln) ln.acquire(); +#define MYWRITERLOCK_ACQUIRE(ln) ln.acquire(); +#define MYREADERLOCK_RELEASE(ln) ln.release(); +#define MYWRITERLOCK_RELEASE(ln) ln.release(); +#endif + +#endif /* _THREADUTILS_ */ diff --git a/rtgui/thumbbrowserentrybase.h b/rtgui/thumbbrowserentrybase.h index a8ac27935..7e1baac07 100644 --- a/rtgui/thumbbrowserentrybase.h +++ b/rtgui/thumbbrowserentrybase.h @@ -22,7 +22,7 @@ #include #include "lwbuttonset.h" #include "thumbnail.h" -#include "guiutils.h" +#include "threadutils.h" class ThumbBrowserBase; class ThumbBrowserEntryBase { diff --git a/rtgui/thumbimageupdater.cc b/rtgui/thumbimageupdater.cc index 4237ad5e9..380f204a8 100644 --- a/rtgui/thumbimageupdater.cc +++ b/rtgui/thumbimageupdater.cc @@ -21,6 +21,7 @@ #include "thumbimageupdater.h" #include #include "guiutils.h" +#include "threadutils.h" #ifdef _OPENMP #include @@ -77,7 +78,13 @@ public: Glib::ThreadPool* threadPool_; + // Need to be a Glib::Threads::Mutex because used in a Glib::Threads::Cond object... + // This is the only exceptions in RT so far, MyMutex is used everywhere else + #ifdef WIN32 Glib::Mutex mutex_; + #else + Glib::Threads::Mutex mutex_; + #endif JobList jobs_; @@ -85,7 +92,11 @@ public: bool inactive_waiting_; + #ifdef WIN32 Glib::Cond inactive_; + #else + Glib::Threads::Cond inactive_; + #endif void processNextJob() @@ -93,7 +104,11 @@ public: Job j; { + #ifdef WIN32 Glib::Mutex::Lock lock(mutex_); + #else + Glib::Threads::Mutex::Lock lock(mutex_); + #endif // nothing to do; could be jobs have been removed if ( jobs_.empty() ) @@ -168,7 +183,12 @@ public: } { + #ifdef WIN32 Glib::Mutex::Lock lock(mutex_); + #else + Glib::Threads::Mutex::Lock lock(mutex_); + #endif + if ( --active_ == 0 && inactive_waiting_ ) @@ -206,7 +226,11 @@ ThumbImageUpdater::add(ThumbBrowserEntryBase* tbe, bool* priority, bool upgrade, return; } + #ifdef WIN32 Glib::Mutex::Lock lock(impl_->mutex_); + #else + Glib::Threads::Mutex::Lock lock(impl_->mutex_); + #endif // look up if an older version is in the queue Impl::JobList::iterator i(impl_->jobs_.begin()); @@ -239,7 +263,11 @@ ThumbImageUpdater::removeJobs(ThumbImageUpdateListener* listener) { DEBUG("removeJobs(%p)",listener); + #ifdef WIN32 Glib::Mutex::Lock lock(impl_->mutex_); + #else + Glib::Threads::Mutex::Lock lock(impl_->mutex_); + #endif for( Impl::JobList::iterator i(impl_->jobs_.begin()); i != impl_->jobs_.end(); ) { @@ -271,8 +299,11 @@ ThumbImageUpdater::removeAllJobs(void) { DEBUG("stop"); - + #ifdef WIN32 Glib::Mutex::Lock lock(impl_->mutex_); + #else + Glib::Threads::Mutex::Lock lock(impl_->mutex_); + #endif impl_->jobs_.clear(); diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 01809030c..bd27b6547 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -45,6 +45,8 @@ Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageDa } else loadProcParams (); + + // should be safe to use the unprotected version of loadThumbnail, since we are in the constructor _loadThumbnail (); generateExifDateTimeStrings (); @@ -165,11 +167,12 @@ bool Thumbnail::isSupported () { } const ProcParams& Thumbnail::getProcParams () { - // TODO: Check for Linux - #ifdef WIN32 - Glib::Mutex::Lock lock(mutex); - #endif + MyMutex::MyLock lock(mutex); + return getProcParamsU(); +} +// Unprotected version of getProcParams, when +const ProcParams& Thumbnail::getProcParamsU () { if (pparamsValid) return pparams; else { @@ -239,10 +242,7 @@ void Thumbnail::notifylisterners_procParamsChanged(int whoChangedIt){ * ProcParams (sidecar or cache file). */ void Thumbnail::loadProcParams () { - // TODO: Check for Linux - #ifdef WIN32 - Glib::Mutex::Lock lock(mutex); - #endif + MyMutex::MyLock lock(mutex); pparamsValid = false; pparams.setDefaults(); @@ -278,11 +278,9 @@ void Thumbnail::clearProcParams (int whoClearedIt) { the "clear profile" will lead to execution of ProcParams::setDefaults (the CPB is NOT called) to set the params values and will preserve rank/colorlabel/inTrash in the param file. */ - - // TODO: Check for Linux - #ifdef WIN32 - Glib::Mutex::Lock lock(mutex); - #endif + + { + MyMutex::MyLock lock(mutex); // preserve rank, colorlabel and inTrash across clear int rank = getRank(); @@ -326,6 +324,8 @@ void Thumbnail::clearProcParams (int whoClearedIt) { safe_g_remove (fname_); } + } // end of mutex lock + for (size_t i=0; iprocParamsChanged (this, whoClearedIt); } @@ -336,15 +336,14 @@ bool Thumbnail::hasProcParams () { } void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoChangedIt, bool updateCacheNow) { - // TODO: Check for Linux - #ifdef WIN32 - Glib::Mutex::Lock lock(mutex); - #endif - - if (pparams.sharpening.threshold.isDouble() != pp.sharpening.threshold.isDouble()) - printf("WARNING: Sharpening different!\n"); - if (pparams.vibrance.psthreshold.isDouble() != pp.vibrance.psthreshold.isDouble()) - printf("WARNING: Vibrance different!\n"); + + { + MyMutex::MyLock lock(mutex); + + if (pparams.sharpening.threshold.isDouble() != pp.sharpening.threshold.isDouble()) + printf("WARNING: Sharpening different!\n"); + if (pparams.vibrance.psthreshold.isDouble() != pp.vibrance.psthreshold.isDouble()) + printf("WARNING: Vibrance different!\n"); if (pparams!=pp) cfs.recentlySaved = false; @@ -368,6 +367,8 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh if (updateCacheNow) updateCache (); + } // end of mutex lock + for (size_t i=0; iprocParamsChanged (this, whoChangedIt); } @@ -401,14 +402,14 @@ bool Thumbnail::isEnqueued () { void Thumbnail::increaseRef () { - Glib::Mutex::Lock lock(mutex); - ++ref; + MyMutex::MyLock lock(mutex); + ++ref; } void Thumbnail::decreaseRef () { { - Glib::Mutex::Lock lock(mutex); + MyMutex::MyLock lock(mutex); if ( ref == 0 ) { return; @@ -429,10 +430,7 @@ void Thumbnail::getThumbnailSize (int &w, int &h) { } void Thumbnail::getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h) { - // TODO: Check for Linux - #ifdef WIN32 - Glib::Mutex::Lock lock(mutex); - #endif + MyMutex::MyLock lock(mutex); // WARNING: When downscaled, the ratio have loosed a lot of precision, so we can't get back the exact initial dimensions double fw = lastW*lastScale; @@ -455,40 +453,35 @@ void Thumbnail::getFinalSize (const rtengine::procparams::ProcParams& pparams, i rtengine::IImage8* Thumbnail::processThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale) { - Glib::Mutex::Lock lock(mutex); + MyMutex::MyLock lock(mutex); - if ( tpp == 0 ) - { - _loadThumbnail(); - if ( tpp == 0 ) - { - return 0; - } - } - - rtengine::IImage8* image = 0; + if ( tpp == 0 ) { + _loadThumbnail(); + if ( tpp == 0 ) + return 0; + } - if ( cfs.thumbImgType == CacheImageData::QUICK_THUMBNAIL ) - { - // RAW internal thumbnail, no profile yet: just do some rotation etc. - image = tpp->quickProcessImage (pparams, h, rtengine::TI_Nearest, scale); - } - else - { - // Full thumbnail: apply profile - image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.camera, cfs.focalLen, cfs.focalLen35mm, cfs.focusDist, cfs.shutter, cfs.fnumber, cfs.iso, cfs.expcomp, scale ); - } + rtengine::IImage8* image = 0; + + if ( cfs.thumbImgType == CacheImageData::QUICK_THUMBNAIL ) { + // RAW internal thumbnail, no profile yet: just do some rotation etc. + image = tpp->quickProcessImage (pparams, h, rtengine::TI_Nearest, scale); + } + else { + // Full thumbnail: apply profile + image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.camera, cfs.focalLen, cfs.focalLen35mm, cfs.focusDist, cfs.shutter, cfs.fnumber, cfs.iso, cfs.expcomp, scale ); + } tpp->getDimensions(lastW,lastH,lastScale); - delete tpp; - tpp = 0; - return image; + delete tpp; + tpp = 0; + return image; } rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale) { - Glib::Mutex::Lock lock(mutex); + MyMutex::MyLock lock(mutex); if ( cfs.thumbImgType != CacheImageData::QUICK_THUMBNAIL ) { @@ -678,7 +671,7 @@ void Thumbnail::_loadThumbnail(bool firstTrial) { tpp->init (); } - if (!initial_ && tpp) tw = tpp->getImageWidth (getProcParams(), th, imgRatio); // this might return 0 if image was just building + if (!initial_ && tpp) tw = tpp->getImageWidth (getProcParamsU(), th, imgRatio); // this might return 0 if image was just building } /* @@ -690,7 +683,7 @@ void Thumbnail::_loadThumbnail(bool firstTrial) { * - LiveThumbData section of the data file */ void Thumbnail::loadThumbnail (bool firstTrial) { - Glib::Mutex::Lock lock(mutex); + MyMutex::MyLock lock(mutex); _loadThumbnail(firstTrial); } @@ -737,7 +730,7 @@ void Thumbnail::_saveThumbnail () { */ void Thumbnail::saveThumbnail () { - Glib::Mutex::Lock lock(mutex); + MyMutex::MyLock lock(mutex); _saveThumbnail(); } @@ -760,13 +753,11 @@ void Thumbnail::updateCache (bool updatePParams, bool updateCacheImageData) { } Thumbnail::~Thumbnail () { - // TODO: Check for Linux - #ifdef WIN32 - Glib::Mutex::Lock lock(mutex); - #endif + mutex.lock(); delete [] lastImg; delete tpp; + mutex.unlock(); } Glib::ustring Thumbnail::getCacheFileName (Glib::ustring subdir) { @@ -860,7 +851,7 @@ bool Thumbnail::openDefaultViewer(int destination) { bool Thumbnail::imageLoad(bool loading) { - Glib::Mutex::Lock lock(mutex); + MyMutex::MyLock lock(mutex); bool previous = imageLoading; if( loading && !previous ){ imageLoading = true; diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index cc7fbbe5c..84d0bbe74 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -27,11 +27,12 @@ #include "../rtengine/rtthumbnail.h" #include "cacheimagedata.h" #include "thumbnaillistener.h" +#include "threadutils.h" class CacheManager; class Thumbnail { - Glib::Mutex mutex; + MyMutex mutex; Glib::ustring fname; // file name corresponding to the thumbnail CacheImageData cfs; // cache entry corresponding to the thumbnail @@ -82,6 +83,7 @@ class Thumbnail { bool hasProcParams (); const rtengine::procparams::ProcParams& getProcParams (); + const rtengine::procparams::ProcParams& getProcParamsU (); // Unprotected version // Use this to create params on demand for update rtengine::procparams::ProcParams* createProcParamsForUpdate (bool returnParams, bool forceCPB);