Solving issue 1684: "thumbnail.cc uses Glib::Mutex recusively" ; this changeset introduce a new MyMutex and MyMutex::MyLock class that has to be used instead of Glib ones

This commit is contained in:
Hombre 2013-08-11 23:33:10 +02:00
parent 987e4dcd89
commit f512d74323
55 changed files with 1037 additions and 751 deletions

View File

@ -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)

View File

@ -27,6 +27,7 @@
#include <math.h>
#include <fftw3.h>
#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);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View File

@ -22,6 +22,7 @@
#include <cstdlib>
#include <vector>
#include <glibmm.h>
#include "../rtgui/threadutils.h"
// Aligned buffer that should be faster
template <class T> class AlignedBuffer {
@ -107,7 +108,7 @@ public:
// Multi processor version, use with OpenMP
template <class T> class AlignedBufferMP {
private:
Glib::Mutex mtx;
MyMutex mtx;
std::vector<AlignedBuffer<T>*> buffers;
size_t size;
@ -121,7 +122,7 @@ public:
}
AlignedBuffer<T>* acquire() {
Glib::Mutex::Lock lock(mtx);
MyMutex::MyLock lock(mtx);
// Find available buffer
for (int i;i<buffers.size();i++) {
@ -139,7 +140,7 @@ public:
}
void release(AlignedBuffer<T>* buffer) {
Glib::Mutex::Lock lock(mtx);
MyMutex::MyLock lock(mtx);
buffer->inUse=false;
}

View File

@ -556,17 +556,17 @@ namespace rtengine {
for (int i=0; i<m_h2; i++) {
if (subsamp_out) {
SynthesisFilterSubsamp (wavcoeffs[0]+i*m_w2, wavcoeffs[1]+i*m_w2, tmpLo+i*m_w, bufferLo, bufferHi, \
SynthesisFilterSubsamp (wavcoeffs[0]+i*m_w2, wavcoeffs[1]+i*m_w2, tmpLo+i*m_w, bufferLo, bufferHi,
filterH, filterH+taps, taps, offset, 1/*pitch*/, m_w/*dstlen*/);
SynthesisFilterSubsamp (wavcoeffs[2]+i*m_w2, wavcoeffs[3]+i*m_w2, tmpHi+i*m_w, bufferLo, bufferHi, \
SynthesisFilterSubsamp (wavcoeffs[2]+i*m_w2, wavcoeffs[3]+i*m_w2, tmpHi+i*m_w, bufferLo, bufferHi,
filterH, filterH+taps, taps, offset, 1/*pitch*/, m_w/*dstlen*/);
//SynthesisFilterSubsampHaar (wavcoeffs[0]+i*m_w2, wavcoeffs[1]+i*m_w2, tmpLo+i*m_w, 1, m_w);//TODO: this is buggy
//SynthesisFilterSubsampHaar (wavcoeffs[2]+i*m_w2, wavcoeffs[3]+i*m_w2, tmpHi+i*m_w, 1, m_w);
} else {
//SynthesisFilter (wavcoeffs[0]+i*m_w2, wavcoeffs[1]+i*m_w2, tmpLo+i*m_w, bufferLo, bufferHi, \
filterH, filterH+taps, taps, offset, 1/*pitch*/, m_w/*dstlen*/);
//SynthesisFilter (wavcoeffs[2]+i*m_w2, wavcoeffs[3]+i*m_w2, tmpHi+i*m_w, bufferLo, bufferHi, \
filterH, filterH+taps, taps, offset, 1/*pitch*/, m_w/*dstlen*/);
//SynthesisFilter (wavcoeffs[0]+i*m_w2, wavcoeffs[1]+i*m_w2, tmpLo+i*m_w, bufferLo, bufferHi,
// filterH, filterH+taps, taps, offset, 1/*pitch*/, m_w/*dstlen*/);
//SynthesisFilter (wavcoeffs[2]+i*m_w2, wavcoeffs[3]+i*m_w2, tmpHi+i*m_w, bufferLo, bufferHi,
// filterH, filterH+taps, taps, offset, 1/*pitch*/, m_w/*dstlen*/);
SynthesisFilterHaar (wavcoeffs[0]+i*m_w2, wavcoeffs[1]+i*m_w2, tmpLo+i*m_w, bufferLo, bufferHi, 1, m_w);
SynthesisFilterHaar (wavcoeffs[2]+i*m_w2, wavcoeffs[3]+i*m_w2, tmpHi+i*m_w, bufferLo, bufferHi, 1, m_w);
}
@ -576,12 +576,12 @@ namespace rtengine {
//OpenMP here
for (int j=0; j<m_w; j++) {
if (subsamp_out) {
SynthesisFilterSubsamp (tmpLo+j, tmpHi+j, dst+j, bufferLo, bufferHi, \
SynthesisFilterSubsamp (tmpLo+j, tmpHi+j, dst+j, bufferLo, bufferHi,
filterV, filterV+taps, taps, offset, m_w/*pitch*/, m_h/*dstlen*/);
//SynthesisFilterSubsampHaar (tmpLo+j, tmpHi+j, dst+j, m_w, m_h);
} else {
//SynthesisFilter (tmpLo+j, tmpHi+j, dst+j, bufferLo, bufferHi, \
filterV, filterV+taps, taps, offset, m_w/*pitch*/, m_h/*dstlen*/);
//SynthesisFilter (tmpLo+j, tmpHi+j, dst+j, bufferLo, bufferHi,
// filterV, filterV+taps, taps, offset, m_w/*pitch*/, m_h/*dstlen*/);
SynthesisFilterHaar (tmpLo+j, tmpHi+j, dst+j, bufferLo, bufferHi, m_w, m_h);
}
}

View File

@ -44,8 +44,8 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) {
TagDirectory *tagDir=ExifManager::parseTIFF(pFile, false);
Tag* tag = tagDir->getTag(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<Glib::ustring, DCPProfile*>::iterator r = profileCache.find (filename);
if (r!=profileCache.end()) return r->second;

View File

@ -22,6 +22,7 @@
#include "imagefloat.h"
#include "curves.h"
#include "../rtgui/threadutils.h"
#include <glibmm.h>
#include <map>
#include <string>
@ -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<Glib::ustring, Glib::ustring> fileStdProfiles;

View File

@ -1,4 +1,3 @@
/*
/*
* This file is part of RawTherapee.
*
@ -55,13 +54,13 @@ 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);
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;

View File

@ -26,6 +26,7 @@
#include "image16.h"
#include "imagesource.h"
#include "procevents.h"
#include "../rtgui/threadutils.h"
namespace rtengine {
@ -52,11 +53,10 @@ class Crop : public DetailedCrop {
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);

View File

@ -16,12 +16,12 @@
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include "iccstore.h"
#ifdef WIN32
#include <winsock2.h>
#else
#include <netinet/in.h>
#endif
#include "iccstore.h"
#include "iccmatrices.h"
#include <glib/gstdio.h>
#include "safegtk.h"
@ -62,7 +62,7 @@ std::vector<std::string> getWorkingProfiles () {
std::vector<std::string> ICCStore::getOutputProfiles () {
Glib::Mutex::Lock lock(mutex_);
MyMutex::MyLock lock(mutex_);
std::vector<std::string> res;
for (std::map<std::string, cmsHPROFILE>::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<std::string, cmsHPROFILE>::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<std::string, cmsHPROFILE>::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();

View File

@ -23,6 +23,7 @@
#include <glibmm.h>
#include <map>
#include <string>
#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<std::string, cmsHPROFILE>& resultProfiles, std::map<std::string, ProfileContent> &resultProfileContents);

View File

@ -23,6 +23,7 @@
#include <glib/gstdio.h>
#include <glibmm.h>
#include <vector>
#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 */

View File

@ -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); }

View File

@ -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); }

View File

@ -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); }

View File

@ -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; }
};
}

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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<Glib::ustring, LCPProfile*>::iterator r = profileCache.find (filename);
if (r!=profileCache.end()) return r->second;

View File

@ -21,6 +21,7 @@
#define _LCP_
#include "imagefloat.h"
#include "../rtgui/threadutils.h"
#include <glibmm.h>
#include <map>
#include <list>
@ -92,7 +93,7 @@ namespace rtengine {
};
class LCPStore {
Glib::Mutex mtx;
MyMutex mtx;
// Maps file name to profile as cache
std::map<Glib::ustring, LCPProfile*> profileCache;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -18,6 +18,7 @@
*/
#include "rtengine.h"
#include "rtthumbnail.h"
#include "../rtgui/options.h"
#include "image8.h"
#include <lcms2.h>
#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 (...) {}
}
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);

View File

@ -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];

View File

@ -19,6 +19,7 @@
#define _BATCHQUEUE_
#include <gtkmm.h>
#include "threadutils.h"
#include "batchqueueentry.h"
#include "../rtengine/rtengine.h"
#include "options.h"

View File

@ -21,6 +21,7 @@
#include <cstring>
#include "guiutils.h"
#include "threadutils.h"
#include "../rtengine/safegtk.h"
#include "multilangmgr.h"

View File

@ -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

View File

@ -21,6 +21,7 @@
#include <glibmm.h>
#include "../rtengine/rtengine.h"
#include "threadutils.h"
#include "thumbnail.h"
class BQEntryUpdateListener {
@ -45,7 +46,7 @@ class BatchQueueEntryUpdater {
bool stopped;
std::list<Job> jqueue;
Glib::Thread* thread;
Glib::Mutex* qMutex;
MyMutex* qMutex;
public:
BatchQueueEntryUpdater ();

View File

@ -36,13 +36,7 @@ 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");
@ -101,8 +95,14 @@ int CacheImageData::load (const Glib::ustring& fname) {
}
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
@ -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);

View File

@ -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");
}

View File

@ -25,6 +25,7 @@
#include "thumbnail.h"
#include <cstdio>
#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);
@ -52,7 +53,7 @@ class CacheManager {
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);

View File

@ -20,6 +20,7 @@
#define __CROPHANDLER__
#include "../rtengine/rtengine.h"
#include "threadutils.h"
#include <gtkmm.h>
class CropHandlerListener {
@ -71,7 +72,7 @@ class CropHandler : public rtengine::DetailedCropListener, public rtengine::Size
Glib::RefPtr<Gdk::Pixbuf> cropPixbuf;
Glib::RefPtr<Gdk::Pixbuf> cropPixbuftrue;
Glib::Mutex cimg;
MyMutex cimg;
CropHandler ();
~CropHandler ();

View File

@ -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<Cairo::Context> cr) {
Glib::Mutex::Lock lock(cropHandler.cimg);
MyMutex::MyLock lock(cropHandler.cimg);
//MyTime t1, t2, t3, t4;

View File

@ -22,6 +22,7 @@
#include "rtwindow.h"
#include <gtk/gtk.h>
#include "rtimage.h"
#include "threadutils.h"
static EditWindow* editWnd = NULL;
@ -36,8 +37,8 @@ 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);

View File

@ -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();

View File

@ -22,6 +22,7 @@
#include <glibmm.h>
#include <list>
#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);

View File

@ -29,7 +29,7 @@
#include "../rtengine/dfmanager.h"
#include "../rtengine/ffmanager.h"
#include "rtimage.h"
#include "guiutils.h"
#include "threadutils.h"
extern Options options;

View File

@ -21,6 +21,7 @@
#include "cursormanager.h"
#include <iomanip>
#include "guiutils.h"
#include "threadutils.h"
#include "../rtengine/safegtk.h"
#include <cstring>

View File

@ -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

View File

@ -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;

View File

@ -20,7 +20,6 @@
#define __GUI_UTILS_
#include <gtkmm.h>
#include <glibmm.h>
#include "../rtengine/rtengine.h"
#include <sstream>
#include <iostream>
@ -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
*/

View File

@ -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 ();

View File

@ -499,18 +499,16 @@ 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) {
return 1;
}
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")){
@ -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");
}
@ -764,9 +760,25 @@ if (keyFile.has_group ("Dialogs")) {
safeDirGet(keyFile, "Dialogs", "LastProfilingReferenceDir", lastProfilingReferenceDir);
}
// --------------------------------------------------------------------------------------------------------
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;
}
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);

View File

@ -172,7 +172,7 @@ void PreviewHandler::imageReady (CropParams cp) {
}
Glib::RefPtr<Gdk::Pixbuf> PreviewHandler::getRoughImage (int x, int y, int w, int h, double zoom) {
Glib::Mutex::Lock lock(previewImgMutex);
MyMutex::MyLock lock(previewImgMutex);
Glib::RefPtr<Gdk::Pixbuf> resPixbuf;
@ -201,7 +201,7 @@ Glib::RefPtr<Gdk::Pixbuf> PreviewHandler::getRoughImage (int x, int y, int w, in
}
Glib::RefPtr<Gdk::Pixbuf> PreviewHandler::getRoughImage (int desiredW, int desiredH, double& zoom_) {
Glib::Mutex::Lock lock(previewImgMutex);
MyMutex::MyLock lock(previewImgMutex);
Glib::RefPtr<Gdk::Pixbuf> resPixbuf;

View File

@ -20,6 +20,7 @@
#define _PREVIEWHANDLER_
#include "../rtengine/rtengine.h"
#include "threadutils.h"
#include <gtkmm.h>
#include <list>
@ -49,10 +50,9 @@ class PreviewHandler : public rtengine::PreviewImageListener {
double previewScale;
PreviewHandlerIdleHelper* pih;
std::list<PreviewListener*> listeners;
Glib::Mutex previewImgMutex;
MyMutex previewImgMutex;
Glib::RefPtr<Gdk::Pixbuf> previewImg;
public:
PreviewHandler ();

View File

@ -20,6 +20,7 @@
#include <set>
#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();
}

View File

@ -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<Glib::ustring,PartialProfile*>::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<Glib::ustring> 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<Glib::ustring,PartialProfile*>::iterator i = partProfiles.begin(); i!=partProfiles.end(); i++)
ret.push_back (i->first);

View File

@ -22,6 +22,7 @@
#include <map>
#include <vector>
#include "../rtengine/rtengine.h"
#include "threadutils.h"
#include "paramsedited.h"
#include <glibmm.h>
@ -34,7 +35,7 @@ class ProfileStore {
STORESTATE_DELETED
} StoreState;
Glib::Mutex *parseMutex;
MyMutex *parseMutex;
StoreState storeState;
std::map<Glib::ustring, rtengine::procparams::PartialProfile*> partProfiles;
void parseDir (const Glib::ustring& pdir);

View File

@ -100,6 +100,7 @@ void RTImage::setPaths(Options &opt) {
else {
configFilename = Glib::build_filename(argv0, Glib::build_filename("themes", Glib::ustring::format(opt.theme, ".iconset")));
}
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"));
@ -107,6 +108,15 @@ void RTImage::setPaths(Options &opt) {
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;

619
rtgui/threadutils.h Normal file
View File

@ -0,0 +1,619 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _THREADUTILS_
#define _THREADUTILS_
#include <glibmm.h>
#include <csignal> // for raise()
#include <cstdio>
#ifdef WIN32
#include <windows.h>
#endif
#ifdef NDEBUG
// We don't trace mutex
#undef TRACE_MYRWMUTEX
#define TRACE_MYRWMUTEX 0
#endif
// Uncomment this if you want to bypass the CMakeList options and force the values
// Of course, DO NOT COMMIT!
//#undef PROTECT_VECTORS
//#define PROTECT_VECTORS 1
//#undef TRACE_MYRWMUTEX
//#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_ */

View File

@ -22,7 +22,7 @@
#include <gtkmm.h>
#include "lwbuttonset.h"
#include "thumbnail.h"
#include "guiutils.h"
#include "threadutils.h"
class ThumbBrowserBase;
class ThumbBrowserEntryBase {

View File

@ -21,6 +21,7 @@
#include "thumbimageupdater.h"
#include <gtkmm.h>
#include "guiutils.h"
#include "threadutils.h"
#ifdef _OPENMP
#include <omp.h>
@ -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();

View File

@ -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();
@ -279,10 +279,8 @@ void Thumbnail::clearProcParams (int whoClearedIt) {
(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; i<listeners.size(); i++)
listeners[i]->procParamsChanged (this, whoClearedIt);
}
@ -336,10 +336,9 @@ 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
{
MyMutex::MyLock lock(mutex);
if (pparams.sharpening.threshold.isDouble() != pp.sharpening.threshold.isDouble())
printf("WARNING: Sharpening different!\n");
@ -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; i<listeners.size(); i++)
listeners[i]->procParamsChanged (this, whoChangedIt);
}
@ -401,14 +402,14 @@ bool Thumbnail::isEnqueued () {
void Thumbnail::increaseRef ()
{
Glib::Mutex::Lock lock(mutex);
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,26 +453,21 @@ 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 )
{
if ( tpp == 0 ) {
_loadThumbnail();
if ( tpp == 0 )
{
return 0;
}
}
rtengine::IImage8* image = 0;
if ( cfs.thumbImgType == CacheImageData::QUICK_THUMBNAIL )
{
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
{
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 );
}
@ -488,7 +481,7 @@ rtengine::IImage8* Thumbnail::processThumbImage (const rtengine::procparams::Pro
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;

View File

@ -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);