try to fix Issue 221: Segfaulting RT. severe mem leak in thumb threading

This commit is contained in:
Andrey Skvortsov
2010-09-13 18:13:20 -07:00
parent 24a457f320
commit da0faec489
2 changed files with 243 additions and 232 deletions

View File

@@ -1,166 +1,175 @@
/* /*
* This file is part of RawTherapee. * This file is part of RawTherapee.
* *
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com> * Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
* *
* RawTherapee is free software: you can redistribute it and/or modify * RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* RawTherapee is distributed in the hope that it will be useful, * RawTherapee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>. * along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <thumbimageupdater.h> #include <thumbimageupdater.h>
#include <gtkmm.h> #include <gtkmm.h>
ThumbImageUpdater thumbImageUpdater; #define threadNum 4 // IF LCMS GETS THREAD SAFETY WE CAN ENABLE MORE THREADS
ThumbImageUpdater thumbImageUpdater;
ThumbImageUpdater::ThumbImageUpdater ()
: tostop(false), stopped(true), qMutex(NULL), startMutex(NULL) { ThumbImageUpdater::ThumbImageUpdater ()
: tostop(false), stopped(true), qMutex(NULL), startMutex(NULL) {
}
threadPool = new Glib::Thread* [threadNum];
void ThumbImageUpdater::add (Thumbnail* t, const rtengine::procparams::ProcParams& params, int height, bool* priority, ThumbImageUpdateListener* l) {
}
if (!qMutex)
qMutex = new Glib::Mutex (); ThumbImageUpdater::~ThumbImageUpdater ()
if (!startMutex) {
startMutex = new Glib::Mutex (); delete threadPool;
}
qMutex->lock ();
// look up if an older version is in the queue void ThumbImageUpdater::add (Thumbnail* t, const rtengine::procparams::ProcParams& params, int height, bool* priority, ThumbImageUpdateListener* l) {
std::list<Job>::iterator i;
for (i=jqueue.begin(); i!=jqueue.end(); i++) if (!qMutex)
if (i->thumbnail==t && i->listener==l) { qMutex = new Glib::Mutex ();
i->pparams = params; if (!startMutex)
i->height = height; startMutex = new Glib::Mutex ();
i->priority = priority;
break; qMutex->lock ();
} // look up if an older version is in the queue
// not found, create and append new job std::list<Job>::iterator i;
if (i==jqueue.end ()) { for (i=jqueue.begin(); i!=jqueue.end(); i++)
Job j; if (i->thumbnail==t && i->listener==l) {
j.thumbnail = t; i->pparams = params;
j.pparams = params; i->height = height;
j.height = height; i->priority = priority;
j.listener = l; break;
j.priority = priority; }
jqueue.push_back (j); // not found, create and append new job
} if (i==jqueue.end ()) {
qMutex->unlock (); Job j;
} j.thumbnail = t;
j.pparams = params;
void ThumbImageUpdater::process () { j.height = height;
j.listener = l;
if (stopped) { j.priority = priority;
#undef THREAD_PRIORITY_NORMAL jqueue.push_back (j);
stopped = false; }
thread = Glib::Thread::create(sigc::mem_fun(*this, &ThumbImageUpdater::process_), (unsigned long int)0, true, true, Glib::THREAD_PRIORITY_NORMAL); qMutex->unlock ();
} }
}
void ThumbImageUpdater::process () {
void ThumbImageUpdater::process_ () {
if (stopped) {
stopped = false; #undef THREAD_PRIORITY_LOW
tostop = false; stopped = false;
thread = Glib::Thread::create(sigc::mem_fun(*this, &ThumbImageUpdater::process_), (unsigned long int)0, true, true, Glib::THREAD_PRIORITY_LOW);
#define threadNum 4 // IF LCMS GETS THREAD SAFETY WE CAN ENABLE MORE THREADS }
Glib::Thread **threadPool = new Glib::Thread* [threadNum]; }
while (!tostop && !jqueue.empty ()) { void ThumbImageUpdater::process_ () {
qMutex->lock (); stopped = false;
int threads = 0; tostop = false;
for (; threads<threadNum && !jqueue.empty (); threads++) {
// find first entry having update priority, if any
std::list<Job>::iterator i; while (!tostop && !jqueue.empty ()) {
for (i=jqueue.begin (); i!=jqueue.end(); i++)
if (*(i->priority)) qMutex->lock ();
break; int threads = 0;
if (i==jqueue.end()) for (; threads<threadNum && !jqueue.empty (); threads++) {
i = jqueue.begin(); // find first entry having update priority, if any
Job current = *i; std::list<Job>::iterator i;
jqueue.erase (i); for (i=jqueue.begin (); i!=jqueue.end(); i++)
if (current.listener) if (*(i->priority))
threadPool[threads] = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ThumbImageUpdater::processJob), current), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); break;
else if (i==jqueue.end())
threadPool[threads] = NULL; i = jqueue.begin();
} Job current = *i;
qMutex->unlock (); jqueue.erase (i);
if (current.listener)
for (int j=0; j<threads; j++) threadPool[threads] = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ThumbImageUpdater::processJob), current), 0, true, true, Glib::THREAD_PRIORITY_LOW);
if (threadPool[j]) //else
threadPool[j]->join (); // threadPool[threads] = NULL;
} }
stopped = true; qMutex->unlock ();
}
for (int j=0; j<threads; j++)
void ThumbImageUpdater::processJob (Job current) { if (threadPool[j])
threadPool[j]->join ();
if (current.listener) {
double scale = 1.0; for(int j =0; j <threadNum;j++)
rtengine::IImage8* img = current.thumbnail->processThumbImage (current.pparams, current.height, scale); threadPool[j] = NULL;
if (img) }
current.listener->updateImage (img, scale, current.pparams.crop); stopped = true;
} }
} void ThumbImageUpdater::processJob (Job current) {
void ThumbImageUpdater::stop () { if (current.listener) {
double scale = 1.0;
if (stopped) { rtengine::IImage8* img = current.thumbnail->processThumbImage (current.pparams, current.height, scale);
tostop = true; if (img)
return; } current.listener->updateImage (img, scale, current.pparams.crop);
}
gdk_threads_leave();
tostop = true; }
Glib::Thread::self()->yield();
if (!stopped) void ThumbImageUpdater::stop () {
thread->join ();
gdk_threads_enter(); if (stopped) {
} tostop = true;
return; }
void ThumbImageUpdater::removeJobs () {
gdk_threads_leave();
if (!qMutex) tostop = true;
return; Glib::Thread::self()->yield();
if (!stopped)
qMutex->lock (); thread->join ();
while (!jqueue.empty()) gdk_threads_enter();
jqueue.pop_front (); }
qMutex->unlock ();
} void ThumbImageUpdater::removeJobs () {
void ThumbImageUpdater::removeJobs (ThumbImageUpdateListener* listener) { if (!qMutex)
return;
if (!qMutex)
return; qMutex->lock ();
while (!jqueue.empty())
qMutex->lock (); jqueue.pop_front ();
bool ready = false; qMutex->unlock ();
while (!ready) { }
ready = true;
std::list<Job>::iterator i; void ThumbImageUpdater::removeJobs (ThumbImageUpdateListener* listener) {
for (i=jqueue.begin(); i!=jqueue.end(); i++)
if (i->listener == listener) { if (!qMutex)
jqueue.erase (i); return;
ready = false;
break; qMutex->lock ();
} bool ready = false;
} while (!ready) {
qMutex->unlock (); ready = true;
} std::list<Job>::iterator i;
for (i=jqueue.begin(); i!=jqueue.end(); i++)
void ThumbImageUpdater::terminate () { if (i->listener == listener) {
jqueue.erase (i);
stop (); ready = false;
removeJobs (); break;
} }
}
qMutex->unlock ();
}
void ThumbImageUpdater::terminate () {
stop ();
removeJobs ();
}

View File

@@ -1,66 +1,68 @@
/* /*
* This file is part of RawTherapee. * This file is part of RawTherapee.
* *
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com> * Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
* *
* RawTherapee is free software: you can redistribute it and/or modify * RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* RawTherapee is distributed in the hope that it will be useful, * RawTherapee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>. * along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _THUMBIMAGEUPDATER_ #ifndef _THUMBIMAGEUPDATER_
#define _THUMBIMAGEUPDATER_ #define _THUMBIMAGEUPDATER_
#include <glibmm.h> #include <glibmm.h>
#include <rtengine.h> #include <rtengine.h>
#include <thumbnail.h> #include <thumbnail.h>
class ThumbImageUpdateListener { class ThumbImageUpdateListener {
public: public:
virtual void updateImage (rtengine::IImage8* img, double scale, rtengine::procparams::CropParams cropParams) {} virtual void updateImage (rtengine::IImage8* img, double scale, rtengine::procparams::CropParams cropParams) {}
}; };
class ThumbImageUpdater { class ThumbImageUpdater {
struct Job { struct Job {
Thumbnail* thumbnail; Thumbnail* thumbnail;
rtengine::procparams::ProcParams pparams; rtengine::procparams::ProcParams pparams;
int height; int height;
bool* priority; bool* priority;
ThumbImageUpdateListener* listener; ThumbImageUpdateListener* listener;
}; };
protected: protected:
bool tostop; bool tostop;
bool stopped; bool stopped;
std::list<Job> jqueue; std::list<Job> jqueue;
Glib::Thread* thread; Glib::Thread* thread;
Glib::Mutex* qMutex; Glib::Mutex* qMutex;
Glib::Mutex* startMutex; Glib::Mutex* startMutex;
Glib::Thread **threadPool;
public:
ThumbImageUpdater (); public:
ThumbImageUpdater ();
void add (Thumbnail* t, const rtengine::procparams::ProcParams& params, int height, bool* priority, ThumbImageUpdateListener* l); ~ThumbImageUpdater ();
void process ();
void stop (); void add (Thumbnail* t, const rtengine::procparams::ProcParams& params, int height, bool* priority, ThumbImageUpdateListener* l);
void removeJobs (); void process ();
void removeJobs (ThumbImageUpdateListener* listener); void stop ();
void terminate (); void removeJobs ();
void removeJobs (ThumbImageUpdateListener* listener);
void process_ (); void terminate ();
void processJob (Job current);
}; void process_ ();
void processJob (Job current);
extern ThumbImageUpdater thumbImageUpdater; };
#endif extern ThumbImageUpdater thumbImageUpdater;
#endif