From da0faec4893a821b9555ea2c83535bc4fe41a2a3 Mon Sep 17 00:00:00 2001 From: Andrey Skvortsov Date: Mon, 13 Sep 2010 18:13:20 -0700 Subject: [PATCH] try to fix Issue 221: Segfaulting RT. severe mem leak in thumb threading --- rtgui/thumbimageupdater.cc | 341 +++++++++++++++++++------------------ rtgui/thumbimageupdater.h | 134 ++++++++------- 2 files changed, 243 insertions(+), 232 deletions(-) diff --git a/rtgui/thumbimageupdater.cc b/rtgui/thumbimageupdater.cc index b4c81d98a..2849f53a2 100644 --- a/rtgui/thumbimageupdater.cc +++ b/rtgui/thumbimageupdater.cc @@ -1,166 +1,175 @@ -/* - * 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 . - */ -#include -#include - -ThumbImageUpdater thumbImageUpdater; - -ThumbImageUpdater::ThumbImageUpdater () - : tostop(false), stopped(true), qMutex(NULL), startMutex(NULL) { - -} - -void ThumbImageUpdater::add (Thumbnail* t, const rtengine::procparams::ProcParams& params, int height, bool* priority, ThumbImageUpdateListener* l) { - - if (!qMutex) - qMutex = new Glib::Mutex (); - if (!startMutex) - startMutex = new Glib::Mutex (); - - qMutex->lock (); - // look up if an older version is in the queue - std::list::iterator i; - for (i=jqueue.begin(); i!=jqueue.end(); i++) - if (i->thumbnail==t && i->listener==l) { - i->pparams = params; - i->height = height; - i->priority = priority; - break; - } - // not found, create and append new job - if (i==jqueue.end ()) { - Job j; - j.thumbnail = t; - j.pparams = params; - j.height = height; - j.listener = l; - j.priority = priority; - jqueue.push_back (j); - } - qMutex->unlock (); -} - -void ThumbImageUpdater::process () { - - if (stopped) { - #undef THREAD_PRIORITY_NORMAL - stopped = false; - thread = Glib::Thread::create(sigc::mem_fun(*this, &ThumbImageUpdater::process_), (unsigned long int)0, true, true, Glib::THREAD_PRIORITY_NORMAL); - } -} - -void ThumbImageUpdater::process_ () { - - stopped = false; - tostop = false; - - #define threadNum 4 // IF LCMS GETS THREAD SAFETY WE CAN ENABLE MORE THREADS - Glib::Thread **threadPool = new Glib::Thread* [threadNum]; - - while (!tostop && !jqueue.empty ()) { - - qMutex->lock (); - int threads = 0; - for (; threads::iterator i; - for (i=jqueue.begin (); i!=jqueue.end(); i++) - if (*(i->priority)) - break; - if (i==jqueue.end()) - i = jqueue.begin(); - Job current = *i; - jqueue.erase (i); - if (current.listener) - threadPool[threads] = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ThumbImageUpdater::processJob), current), 0, true, true, Glib::THREAD_PRIORITY_NORMAL); - else - threadPool[threads] = NULL; - } - qMutex->unlock (); - - for (int j=0; jjoin (); - } - stopped = true; -} - -void ThumbImageUpdater::processJob (Job current) { - - if (current.listener) { - double scale = 1.0; - rtengine::IImage8* img = current.thumbnail->processThumbImage (current.pparams, current.height, scale); - if (img) - current.listener->updateImage (img, scale, current.pparams.crop); - } - -} - -void ThumbImageUpdater::stop () { - - if (stopped) { - tostop = true; - return; } - - gdk_threads_leave(); - tostop = true; - Glib::Thread::self()->yield(); - if (!stopped) - thread->join (); - gdk_threads_enter(); -} - -void ThumbImageUpdater::removeJobs () { - - if (!qMutex) - return; - - qMutex->lock (); - while (!jqueue.empty()) - jqueue.pop_front (); - qMutex->unlock (); -} - -void ThumbImageUpdater::removeJobs (ThumbImageUpdateListener* listener) { - - if (!qMutex) - return; - - qMutex->lock (); - bool ready = false; - while (!ready) { - ready = true; - std::list::iterator i; - for (i=jqueue.begin(); i!=jqueue.end(); i++) - if (i->listener == listener) { - jqueue.erase (i); - ready = false; - break; - } - } - qMutex->unlock (); -} - -void ThumbImageUpdater::terminate () { - - stop (); - removeJobs (); -} - - +/* + * 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 . + */ +#include +#include + +#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) { + + threadPool = new Glib::Thread* [threadNum]; + +} + +ThumbImageUpdater::~ThumbImageUpdater () +{ + delete threadPool; +} + +void ThumbImageUpdater::add (Thumbnail* t, const rtengine::procparams::ProcParams& params, int height, bool* priority, ThumbImageUpdateListener* l) { + + if (!qMutex) + qMutex = new Glib::Mutex (); + if (!startMutex) + startMutex = new Glib::Mutex (); + + qMutex->lock (); + // look up if an older version is in the queue + std::list::iterator i; + for (i=jqueue.begin(); i!=jqueue.end(); i++) + if (i->thumbnail==t && i->listener==l) { + i->pparams = params; + i->height = height; + i->priority = priority; + break; + } + // not found, create and append new job + if (i==jqueue.end ()) { + Job j; + j.thumbnail = t; + j.pparams = params; + j.height = height; + j.listener = l; + j.priority = priority; + jqueue.push_back (j); + } + qMutex->unlock (); +} + +void ThumbImageUpdater::process () { + + if (stopped) { + #undef THREAD_PRIORITY_LOW + stopped = false; + thread = Glib::Thread::create(sigc::mem_fun(*this, &ThumbImageUpdater::process_), (unsigned long int)0, true, true, Glib::THREAD_PRIORITY_LOW); + } +} + +void ThumbImageUpdater::process_ () { + + stopped = false; + tostop = false; + + + while (!tostop && !jqueue.empty ()) { + + qMutex->lock (); + int threads = 0; + for (; threads::iterator i; + for (i=jqueue.begin (); i!=jqueue.end(); i++) + if (*(i->priority)) + break; + if (i==jqueue.end()) + i = jqueue.begin(); + Job current = *i; + jqueue.erase (i); + if (current.listener) + threadPool[threads] = Glib::Thread::create(sigc::bind(sigc::mem_fun(*this, &ThumbImageUpdater::processJob), current), 0, true, true, Glib::THREAD_PRIORITY_LOW); + //else + // threadPool[threads] = NULL; + } + qMutex->unlock (); + + for (int j=0; jjoin (); + + for(int j =0; j processThumbImage (current.pparams, current.height, scale); + if (img) + current.listener->updateImage (img, scale, current.pparams.crop); + } + +} + +void ThumbImageUpdater::stop () { + + if (stopped) { + tostop = true; + return; } + + gdk_threads_leave(); + tostop = true; + Glib::Thread::self()->yield(); + if (!stopped) + thread->join (); + gdk_threads_enter(); +} + +void ThumbImageUpdater::removeJobs () { + + if (!qMutex) + return; + + qMutex->lock (); + while (!jqueue.empty()) + jqueue.pop_front (); + qMutex->unlock (); +} + +void ThumbImageUpdater::removeJobs (ThumbImageUpdateListener* listener) { + + if (!qMutex) + return; + + qMutex->lock (); + bool ready = false; + while (!ready) { + ready = true; + std::list::iterator i; + for (i=jqueue.begin(); i!=jqueue.end(); i++) + if (i->listener == listener) { + jqueue.erase (i); + ready = false; + break; + } + } + qMutex->unlock (); +} + +void ThumbImageUpdater::terminate () { + + stop (); + removeJobs (); +} + + diff --git a/rtgui/thumbimageupdater.h b/rtgui/thumbimageupdater.h index e93074451..16bc8ec50 100644 --- a/rtgui/thumbimageupdater.h +++ b/rtgui/thumbimageupdater.h @@ -1,66 +1,68 @@ -/* - * 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 _THUMBIMAGEUPDATER_ -#define _THUMBIMAGEUPDATER_ - -#include -#include -#include - -class ThumbImageUpdateListener { - - public: - virtual void updateImage (rtengine::IImage8* img, double scale, rtengine::procparams::CropParams cropParams) {} -}; - -class ThumbImageUpdater { - - struct Job { - Thumbnail* thumbnail; - rtengine::procparams::ProcParams pparams; - int height; - bool* priority; - ThumbImageUpdateListener* listener; - }; - - protected: - bool tostop; - bool stopped; - std::list jqueue; - Glib::Thread* thread; - Glib::Mutex* qMutex; - Glib::Mutex* startMutex; - - public: - ThumbImageUpdater (); - - void add (Thumbnail* t, const rtengine::procparams::ProcParams& params, int height, bool* priority, ThumbImageUpdateListener* l); - void process (); - void stop (); - void removeJobs (); - void removeJobs (ThumbImageUpdateListener* listener); - void terminate (); - - void process_ (); - void processJob (Job current); -}; - -extern ThumbImageUpdater thumbImageUpdater; - -#endif +/* + * 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 _THUMBIMAGEUPDATER_ +#define _THUMBIMAGEUPDATER_ + +#include +#include +#include + +class ThumbImageUpdateListener { + + public: + virtual void updateImage (rtengine::IImage8* img, double scale, rtengine::procparams::CropParams cropParams) {} +}; + +class ThumbImageUpdater { + + struct Job { + Thumbnail* thumbnail; + rtengine::procparams::ProcParams pparams; + int height; + bool* priority; + ThumbImageUpdateListener* listener; + }; + + protected: + bool tostop; + bool stopped; + std::list jqueue; + Glib::Thread* thread; + Glib::Mutex* qMutex; + Glib::Mutex* startMutex; + Glib::Thread **threadPool; + + public: + ThumbImageUpdater (); + ~ThumbImageUpdater (); + + void add (Thumbnail* t, const rtengine::procparams::ProcParams& params, int height, bool* priority, ThumbImageUpdateListener* l); + void process (); + void stop (); + void removeJobs (); + void removeJobs (ThumbImageUpdateListener* listener); + void terminate (); + + void process_ (); + void processJob (Job current); +}; + +extern ThumbImageUpdater thumbImageUpdater; + +#endif