• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

ThreadWeaver

JobCollection.cpp

Go to the documentation of this file.
00001 /* -*- C++ -*-
00002 
00003 This file implements the JobCollection class.
00004 
00005 $ Author: Mirko Boehm $
00006 $ Copyright: (C) 2004, 2005, 2006 Mirko Boehm $
00007 $ Contact: mirko@kde.org
00008 http://www.kde.org
00009 http://www.hackerbuero.org $
00010 
00011    This library is free software; you can redistribute it and/or
00012    modify it under the terms of the GNU Library General Public
00013    License as published by the Free Software Foundation; either
00014    version 2 of the License, or (at your option) any later version.
00015 
00016    This library is distributed in the hope that it will be useful,
00017    but WITHOUT ANY WARRANTY; without even the implied warranty of
00018    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019    Library General Public License for more details.
00020 
00021    You should have received a copy of the GNU Library General Public License
00022    along with this library; see the file COPYING.LIB.  If not, write to
00023    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00024    Boston, MA 02110-1301, USA.
00025 
00026 $Id: DebuggingAids.h 30 2005-08-16 16:16:04Z mirko $
00027 */
00028 
00029 #include "JobCollection.h"
00030 #include "JobCollection_p.h"
00031 
00032 #include "WeaverInterface.h"
00033 #include "DebuggingAids.h"
00034 
00035 #include <QtCore/QList>
00036 #include <QtCore/QObject>
00037 #include <QtCore/QPointer>
00038 
00039 #include "DependencyPolicy.h"
00040 
00041 using namespace ThreadWeaver;
00042 
00043 JobCollectionJobRunner::JobCollectionJobRunner ( JobCollection* collection, Job* payload, QObject* parent )
00044     : Job( parent )
00045     , m_payload( payload )
00046     , m_collection( collection )
00047 {
00048     Q_ASSERT ( payload ); // will not accept zero jobs
00049 
00050     if ( ! m_payload->objectName().isEmpty() )
00051     {   // this is most useful for debugging...
00052         setObjectName( tr( "JobRunner executing " ) + m_payload->objectName() );
00053     } else {
00054         setObjectName( tr( "JobRunner (unnamed payload)" ) );
00055     }
00056 }
00057 
00058 bool JobCollectionJobRunner::canBeExecuted()
00059 {   // the JobCollectionJobRunner object never have any dependencies:
00060     return m_payload->canBeExecuted();
00061 }
00062 
00063 Job* JobCollectionJobRunner::payload ()
00064 {
00065     return m_payload;
00066 }
00067 
00068 void JobCollectionJobRunner::aboutToBeQueued ( WeaverInterface *weaver )
00069 {
00070     m_payload->aboutToBeQueued( weaver );
00071 }
00072 
00073 void JobCollectionJobRunner::aboutToBeDequeued ( WeaverInterface *weaver )
00074 {
00075     m_payload->aboutToBeDequeued( weaver );
00076 }
00077 
00078 void JobCollectionJobRunner::execute ( Thread *t )
00079 {
00080     if ( m_payload )
00081     {
00082         m_payload->execute ( t );
00083         m_collection->internalJobDone ( m_payload);
00084     } else {
00085         debug ( 1, "JobCollection: job in collection has been deleted." );
00086     }
00087     Job::execute ( t );
00088 }
00089 
00090 int JobCollectionJobRunner::priority () const
00091 {
00092     return m_payload->priority();
00093 }
00094 
00095 void JobCollectionJobRunner::run ()
00096 {
00097 }
00098 
00099 class JobList : public QList <JobCollectionJobRunner*> {};
00100 
00101 class JobCollection::Private
00102 {
00103 public:
00104 
00105     Private()
00106         : elements ( new JobList() )
00107         , weaver ( 0 )
00108         , jobCounter (0)
00109     {}
00110 
00111     ~Private()
00112     {
00113         delete elements;
00114     }
00115 
00116     /* The elements of the collection. */
00117     JobList* elements;
00118 
00119     /* The Weaver interface this collection is queued in. */
00120     WeaverInterface *weaver;
00121 
00122     /* Counter for the finished jobs.
00123        Set to the number of elements when started.
00124        When zero, all elements are done.
00125     */
00126     int jobCounter;
00127 
00128     QMutex mutex;
00129 };
00130 
00131 JobCollection::JobCollection ( QObject *parent )
00132     : Job ( parent )
00133     , d (new Private)
00134 {
00135 }
00136 
00137 JobCollection::~JobCollection()
00138 {   // dequeue all remaining jobs:
00139     if ( d->weaver != 0 ) // still queued
00140         dequeueElements();
00141     // QObject cleanup takes care of the job runners
00142     delete d;
00143 }
00144 
00145 void JobCollection::addJob ( Job *job )
00146 {
00147     REQUIRE( d->weaver == 0 );
00148     REQUIRE( job != 0);
00149     d->elements->append ( new JobCollectionJobRunner( this, job, this ) );
00150 }
00151 
00152 void JobCollection::stop( Job *job )
00153 {   // this only works if there is an event queue executed by the main
00154     // thread, and it is not blocked:
00155     Q_UNUSED( job );
00156     if ( d->weaver != 0 )
00157     {
00158         debug( 4, "JobCollection::stop: dequeueing %p.\n", this);
00159         d->weaver->dequeue( this );
00160     }
00161     // FIXME ENSURE ( d->weaver == 0 ); // verify that aboutToBeDequeued has been called
00162 }
00163 
00164 void JobCollection::aboutToBeQueued ( WeaverInterface *weaver )
00165 {
00166     REQUIRE ( d->weaver == 0 ); // never queue twice
00167 
00168     d->weaver = weaver;
00169 
00170     if ( d->elements->size() > 0 )
00171     {
00172         d->elements->at( 0 )->aboutToBeQueued( weaver );
00173     }
00174 
00175     ENSURE(d->weaver != 0);
00176 }
00177 
00178 void JobCollection::aboutToBeDequeued( WeaverInterface* weaver )
00179 {   //  Q_ASSERT ( d->weaver != 0 );
00180     // I thought: "must have been queued first"
00181     // but the user can queue and dequeue in a suspended Weaver
00182 
00183     if ( d->weaver )
00184     {
00185         dequeueElements();
00186 
00187         d->elements->at( 0 )->aboutToBeDequeued( weaver );
00188     }
00189 
00190     d->weaver = 0;
00191     ENSURE ( d->weaver == 0 );
00192 }
00193 
00194 void JobCollection::execute ( Thread *t )
00195 {
00196     REQUIRE ( d->weaver != 0);
00197 
00198     // this is async,
00199     // JobTests::JobSignalsAreEmittedAsynchronouslyTest() proves it
00200     emit (started (this));
00201 
00202     if ( d->elements->isEmpty() )
00203     {   // we are just a regular, empty job (sob...):
00204         Job::execute( t );
00205         return;
00206     }
00207 
00208     {   // d->elements is supposedly constant at this time, since we are
00209         // already queued
00210         // set job counter:
00211         QMutexLocker l ( & d->mutex );
00212         d->jobCounter = d->elements->size();
00213 
00214         // queue elements:
00215         for (int index = 1; index < d->elements->size(); ++index)
00216     {
00217             d->weaver->enqueue (d->elements->at(index));
00218     }
00219     }
00220     // this is a hack (but a good one): instead of queueing (this), we
00221     // execute the last job, to avoid to have (this) wait for an
00222     // available thread (the last operation does not get queued in
00223     // aboutToBeQueued() )
00224     // NOTE: this also calls internalJobDone()
00225     d->elements->at( 0 )->execute ( t );
00226 
00227     // do not emit done, done is emitted when the last job called
00228     // internalJobDone()
00229     // also, do not free the queue policies yet, since not the whole job
00230     // is done
00231 }
00232 
00233 Job* JobCollection::jobAt( int i )
00234 {
00235     QMutexLocker l( &d->mutex );
00236     REQUIRE ( i >= 0 && i < d->elements->size() );
00237     return d->elements->at( i )->payload();
00238 }
00239 
00240 const int JobCollection::jobListLength()
00241 {
00242     QMutexLocker l( &d->mutex );
00243     return d->elements->size();
00244 }
00245 
00246 bool JobCollection::canBeExecuted()
00247 {
00248     bool inheritedCanRun = true;
00249 
00250     QMutexLocker l( &d->mutex );
00251 
00252     if ( d->elements->size() > 0 )
00253     {
00254         inheritedCanRun = d->elements->at( 0 )->canBeExecuted();
00255     }
00256 
00257     return Job::canBeExecuted() && inheritedCanRun;
00258 }
00259 
00260 void JobCollection::internalJobDone ( Job* job )
00261 {
00262     REQUIRE (job != 0);
00263     Q_UNUSED (job);
00264 
00265     QMutexLocker l( &d->mutex );
00266 
00267     if ( d->jobCounter == 0 )
00268     {   // there is a small chance that (this) has been dequeued in the
00269         // meantime, in this case, there is nothing left to clean up:
00270         d->weaver = 0;
00271         return;
00272     }
00273 
00274     --d->jobCounter;
00275 
00276     if (d->jobCounter == 0)
00277     {
00278         if (! success())
00279         {
00280             emit failed(this);
00281         }
00282 
00283         finalCleanup();
00284     }
00285     ENSURE (d->jobCounter >= 0);
00286 }
00287 
00288 void JobCollection::finalCleanup()
00289 {
00290     freeQueuePolicyResources();
00291     setFinished(true);
00292     d->weaver = 0;
00293     emit done(this);
00294 }
00295 
00296 void JobCollection::dequeueElements()
00297 {   // dequeue everything:
00298     QMutexLocker l( &d->mutex );
00299 
00300     if ( d->weaver != 0 )
00301     {
00302         for ( int index = 1; index < d->elements->size(); ++index )
00303         {
00304             if ( d->elements->at( index ) && ! d->elements->at( index )->isFinished() ) // ... a QPointer
00305             {
00306                 debug( 4, "JobCollection::dequeueElements: dequeueing %p.\n",
00307                        d->elements->at( index ) );
00308                 d->weaver->dequeue ( d->elements->at( index ) );
00309             } else {
00310                 debug( 4, "JobCollection::dequeueElements: not dequeueing %p, already finished.\n",
00311                        d->elements->at( index ) );
00312             }
00313         }
00314 
00315         if (d->jobCounter != 0)
00316     { // if jobCounter is not zero, then we where waiting for the
00317       // last job to finish before we would have freed our queue
00318       // policies, but in this case we have to do it here:
00319             finalCleanup();
00320     }
00321         d->jobCounter = 0;
00322     }
00323 }
00324 
00325 #include "JobCollection.moc"
00326 #include "JobCollection_p.moc"

ThreadWeaver

Skip menu "ThreadWeaver"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   WTF
  • KJSEmbed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  •   core
  • Phonon
  •   Backend
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal