kdecore Library: kresolvermanager.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# kresolvermanager.cpp

    00001 /*  -*- C++ -*-
    00002  *  Copyright (C) 2003-2005 Thiago Macieira <thiago.macieira@kdemail.net>
    00003  *
    00004  *
    00005  *  Permission is hereby granted, free of charge, to any person obtaining
    00006  *  a copy of this software and associated documentation files (the
    00007  *  "Software"), to deal in the Software without restriction, including
    00008  *  without limitation the rights to use, copy, modify, merge, publish,
    00009  *  distribute, sublicense, and/or sell copies of the Software, and to
    00010  *  permit persons to whom the Software is furnished to do so, subject to
    00011  *  the following conditions:
    00012  *
    00013  *  The above copyright notice and this permission notice shall be included
    00014  *  in all copies or substantial portions of the Software.
    00015  *
    00016  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    00017  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    00018  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    00019  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    00020  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    00021  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    00022  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    00023  */
    00024
    00025 #include "config.h"
    00026
    00027 #include <sys/types.h>
    00028 #include <netinet/in.h>
    00029 #include <limits.h>
    00030 #include <unistd.h>     // only needed for pid_t
    00031
    00032 #ifdef HAVE_RES_INIT
    00033 # include <sys/stat.h>
    00034 # include <resolv.h>
    00035 extern "C" {
    00036 #   include <arpa/nameser.h>
    00037 }
    00038 # include <time.h>
    00039 #endif
    00040
    00041 #include <qapplication.h>
    00042 #include <qstring.h>
    00043 #include <qcstring.h>
    00044 #include <qptrlist.h>
    00045 #include <qtimer.h>
    00046 #include <qmutex.h>
    00047 #include <qthread.h>
    00048 #include <qwaitcondition.h>
    00049 #include <qsemaphore.h>
    00050
    00051 #include <kde_file.h>
    00052 #include <kdebug.h>
    00053 #include "kresolver.h"
    00054 #include "kresolver_p.h"
    00055 #include "kresolverworkerbase.h"
    00056 #include "kresolverstandardworkers_p.h"
    00057
    00058 using namespace KNetwork;
    00059 using namespace KNetwork::Internal;
    00060
    00061 /*
    00062  * Explanation on how the resolver system works
    00063
    00064    When KResolver::start is called, it calls KResolverManager::enqueue to add
    00065    an entry to the queue. KResolverManager::enqueue will verify the availability
    00066    of a worker thread: if one is available, it will dispatch the request to it.
    00067    If no threads are available, it will then decide whether to launch a thread
    00068    or to queue for the future.
    00069
    00070    (This process is achieved by always queueing the new request, starting a
    00071    new thread if necessary and then notifying of the availability of data
    00072    to all worker threads).
    00073
    00074  * Worker thread
    00075    A new thread, when started, will enter its event loop
    00076    immediately. That is, it'll first try to acquire new data to
    00077    process, which means it will lock and unlock the manager mutex in
    00078    the process.
    00079
    00080    If it finds no new data, it'll wait on the feedWorkers condition
    00081    for a certain maximum time. If that time expires and there's still
    00082    no data, the thread will exit, in order to save system resources.
    00083
    00084    If it finds data, however, it'll set up and call the worker class
    00085    that has been selected by the manager. Once that worker is done,
    00086    the thread releases the data through KResolverManager::releaseData.
    00087
    00088  * Data requesting/releasing
    00089    A worker thread always calls upon functions on the resolver manager
    00090    in order to acquire and release data.
    00091
    00092    When data is being requested, the KResolverManager::requestData
    00093    function will look the currentRequests list and return the first
    00094    Queued request it finds, while marking it to be InProgress.
    00095
    00096    When the worker class has returned, the worker thread will release
    00097    that data through the KResolverManager::releaseData function. If the
    00098    worker class has requested no further data (nRequests == 0), the
    00099    request's status is marked to be Done. It'll then look at the
    00100    requestor for that data: if it was requested by another worker,
    00101    it'll decrement the requests count for that one and add the results
    00102    to a list. And, finally, if the requests count for the requestor
    00103    becomes 0, it'll repeat this process for the requestor as well
    00104    (change status to Done, check for a requestor).
    00105  */
    00106
    00107 namespace
    00108 {
    00109
    00110 /*
    00111  * This class is used to control the access to the
    00112  * system's resolver API.
    00113  *
    00114  * It is necessary to periodically poll /etc/resolv.conf and reload
    00115  * it if any changes are noticed. This class does exactly that.
    00116  *
    00117  * However, there's also the problem of reloading the structure while
    00118  * some threads are in progress. Therefore, we keep a usage reference count.
    00119  */
    00120 class ResInitUsage
    00121 {
    00122 public:
    00123
    00124 #ifdef HAVE_RES_INIT
    00125   time_t mTime;
    00126   int useCount;
    00127
    00128 # ifndef RES_INIT_THREADSAFE
    00129   QWaitCondition cond;
    00130   QMutex mutex;
    00131 # endif
    00132
    00133   bool shouldResInit()
    00134   {
    00135     // check if /etc/resolv.conf has changed
    00136     KDE_struct_stat st;
    00137     if (KDE_stat("/etc/resolv.conf", &st) != 0)
    00138       return false;
    00139
    00140     if (mTime != st.st_mtime)
    00141       {
    00142     //kdDebug(179) << "shouldResInit: /etc/resolv.conf updated" << endl;
    00143     return true;
    00144       }
    00145     return false;
    00146   }
    00147
    00148   void callResInit()
    00149   {
    00150     if (mTime != 0)
    00151       {
    00152     // don't call it the first time
    00153     // let it be initialised naturally
    00154     //kdDebug(179) << "callResInit: calling res_init()" << endl;
    00155     res_init();
    00156       }
    00157
    00158     KDE_struct_stat st;
    00159     if (KDE_stat("/etc/resolv.conf", &st) == 0)
    00160       mTime = st.st_mtime;
    00161   }
    00162
    00163   ResInitUsage()
    00164     : mTime(0), useCount(0)
    00165   { }
    00166
    00167   /*
    00168    * Marks the end of usage to the resolver tools
    00169    */
    00170   void release()
    00171   {
    00172 # ifndef RES_INIT_THREADSAFE
    00173     QMutexLocker locker(&mutex);
    00174     if (--useCount == 0)
    00175       {
    00176     if (shouldResInit())
    00177       callResInit();
    00178
    00179     // we've reached 0, wake up anyone that's waiting to call res_init
    00180     cond.wakeAll();
    00181       }
    00182 # else
    00183     // do nothing
    00184 # endif
    00185   }
    00186
    00187   /*
    00188    * Marks the beginning of usage of the resolver API
    00189    */
    00190   void acquire()
    00191   {
    00192 # ifndef RES_INIT_THREADSAFE
    00193     mutex.lock();
    00194
    00195     if (shouldResInit())
    00196       {
    00197     if (useCount)
    00198       {
    00199         // other threads are already using the API, so wait till
    00200         // it's all clear
    00201         // the thread that emits this condition will also call res_init
    00202         //qDebug("ResInitUsage: waiting for libresolv to be clear");
    00203         cond.wait(&mutex);
    00204       }
    00205     else
    00206       // we're clear
    00207       callResInit();
    00208       }
    00209     useCount++;
    00210     mutex.unlock();
    00211
    00212 # else
    00213     if (shouldResInit())
    00214       callResInit();
    00215
    00216 # endif
    00217   }
    00218
    00219 #else
    00220   ResInitUsage()
    00221   { }
    00222
    00223   bool shouldResInit()
    00224   { return false; }
    00225
    00226   void acquire()
    00227   { }
    00228
    00229   void release()
    00230   { }
    00231 #endif
    00232
    00233 } resInit;
    00234
    00235 } // anonymous namespace
    00236
    00237 /*
    00238  * parameters
    00239  */
    00240 // a thread will try maxThreadRetries to get data, waiting at most
    00241 // maxThreadWaitTime milliseconds between each attempt. After that, it'll
    00242 // exit
    00243 static const int maxThreadWaitTime = 2000; // 2 seconds
    00244 static const int maxThreads = 5;
    00245
    00246 static pid_t pid;       // FIXME -- disable when everything is ok
    00247
    00248 KResolverThread::KResolverThread()
    00249   : data(0L)
    00250 {
    00251 }
    00252
    00253 // remember! This function runs in a separate thread!
    00254 void KResolverThread::run()
    00255 {
    00256   // initialisation
    00257   // enter the loop already
    00258
    00259   //qDebug("KResolverThread(thread %u/%p): started", pid, (void*)QThread::currentThread());
    00260   KResolverManager::manager()->registerThread(this);
    00261   while (true)
    00262     {
    00263       data = KResolverManager::manager()->requestData(this, ::maxThreadWaitTime);
    00264       //qDebug("KResolverThread(thread %u/%p) got data %p", KResolverManager::pid,
    00265       //       (void*)QThread::currentThread(), (void*)data);
    00266       if (data)
    00267     {
    00268       // yes, we got data
    00269       // process it!
    00270
    00271       // 1) set up
    00272       ;
    00273
    00274       // 2) run it
    00275       data->worker->run();
    00276
    00277       // 3) release data
    00278       KResolverManager::manager()->releaseData(this, data);
    00279
    00280       // now go back to the loop
    00281     }
    00282       else
    00283     break;
    00284     }
    00285
    00286   KResolverManager::manager()->unregisterThread(this);
    00287   //qDebug("KResolverThread(thread %u/%p): exiting", pid, (void*)QThread::currentThread());
    00288 }
    00289
    00290 bool KResolverThread::checkResolver()
    00291 {
    00292   return resInit.shouldResInit();
    00293 }
    00294
    00295 void KResolverThread::acquireResolver()
    00296 {
    00297 #if defined(NEED_MUTEX) && !defined(Q_OS_FREEBSD)
    00298   getXXbyYYmutex.lock();
    00299 #endif
    00300
    00301   resInit.acquire();
    00302 }
    00303
    00304 void KResolverThread::releaseResolver()
    00305 {
    00306 #if defined(NEED_MUTEX) && !defined(Q_OS_FREEBSD)
    00307   getXXbyYYmutex.unlock();
    00308 #endif
    00309
    00310   resInit.release();
    00311 }
    00312
    00313 static KResolverManager *globalManager;
    00314
    00315 KResolverManager* KResolverManager::manager()
    00316 {
    00317   if (globalManager == 0L)
    00318     new KResolverManager();
    00319   return globalManager;
    00320 }
    00321
    00322 KResolverManager::KResolverManager()
    00323   : runningThreads(0), availableThreads(0)
    00324 {
    00325   globalManager = this;
    00326   workers.setAutoDelete(true);
    00327   currentRequests.setAutoDelete(true);
    00328   initStandardWorkers();
    00329
    00330   pid = getpid();
    00331 }
    00332
    00333 KResolverManager::~KResolverManager()
    00334 {
    00335   // this should never be called
    00336
    00337   // kill off running threads
    00338   for (workers.first(); workers.current(); workers.next())
    00339     workers.current()->terminate();
    00340 }
    00341
    00342 void KResolverManager::registerThread(KResolverThread* )
    00343 {
    00344 }
    00345
    00346 void KResolverManager::unregisterThread(KResolverThread*)
    00347 {
    00348   runningThreads--;
    00349 }
    00350
    00351 // this function is called by KResolverThread::run
    00352 RequestData* KResolverManager::requestData(KResolverThread *th, int maxWaitTime)
    00353 {
    00355   // This function is called in a worker thread!!
    00357
    00358   // lock the mutex, so that the manager thread or other threads won't
    00359   // interfere.
    00360   QMutexLocker locker(&mutex);
    00361   RequestData *data = findData(th);
    00362
    00363   if (data)
    00364     // it found something, that's good
    00365     return data;
    00366
    00367   // nope, nothing found; sleep for a while
    00368   availableThreads++;
    00369   feedWorkers.wait(&mutex, maxWaitTime);
    00370   availableThreads--;
    00371
    00372   data = findData(th);
    00373   return data;
    00374 }
    00375
    00376 RequestData* KResolverManager::findData(KResolverThread* th)
    00377 {
    00379   // This function is called by @ref requestData above and must
    00380   // always be called with a locked mutex
    00382
    00383   // now find data to be processed
    00384   for (RequestData *curr = newRequests.first(); curr; curr = newRequests.next())
    00385     if (!curr->worker->m_finished)
    00386       {
    00387     // found one
    00388     if (curr->obj)
    00389       curr->obj->status = KResolver::InProgress;
    00390     curr->worker->th = th;
    00391
    00392     // move it to the currentRequests list
    00393     currentRequests.append(newRequests.take());
    00394
    00395     return curr;
    00396       }
    00397
    00398   // found nothing!
    00399   return 0L;
    00400 }
    00401
    00402 // this function is called by KResolverThread::run
    00403 void KResolverManager::releaseData(KResolverThread *, RequestData* data)
    00404 {
    00406   // This function is called in a worker thread!!
    00408
    00409   //qDebug("KResolverManager::releaseData(%u/%p): %p has been released", pid,
    00410 //   (void*)QThread::currentThread(), (void*)data);
    00411
    00412   if (data->obj)
    00413     {
    00414       data->obj->status = KResolver::PostProcessing;
    00415     }
    00416
    00417   data->worker->m_finished = true;
    00418   data->worker->th = 0L;    // this releases the object
    00419
    00420   // handle finished requests
    00421   handleFinished();
    00422 }
    00423
    00424 // this function is called by KResolverManager::releaseData above
    00425 void KResolverManager::handleFinished()
    00426 {
    00427   bool redo = false;
    00428   QPtrQueue<RequestData> doneRequests;
    00429
    00430   mutex.lock();
    00431
    00432   // loop over all items on the currently running list
    00433   // we loop from the last to the first so that we catch requests with "requestors" before
    00434   // we catch the requestor itself.
    00435   RequestData *curr = currentRequests.last();
    00436   while (curr)
    00437     {
    00438       if (curr->worker->th == 0L)
    00439     {
    00440       if (handleFinishedItem(curr))
    00441         {
    00442           doneRequests.enqueue(currentRequests.take());
    00443           if (curr->requestor &&
    00444           curr->requestor->nRequests == 0 &&
    00445           curr->requestor->worker->m_finished)
    00446         // there's a requestor that is now finished
    00447         redo = true;
    00448         }
    00449     }
    00450
    00451       curr = currentRequests.prev();
    00452     }
    00453
    00454   //qDebug("KResolverManager::handleFinished(%u): %d requests to notify", pid, doneRequests.count());
    00455   while (RequestData *d = doneRequests.dequeue())
    00456     doNotifying(d);
    00457
    00458   mutex.unlock();
    00459
    00460   if (redo)
    00461     {
    00462       //qDebug("KResolverManager::handleFinished(%u): restarting processing to catch requestor",
    00463     //     pid);
    00464       handleFinished();
    00465     }
    00466 }
    00467
    00468 // This function is called by KResolverManager::handleFinished above
    00469 bool KResolverManager::handleFinishedItem(RequestData* curr)
    00470
    00471 {
    00472   // for all items that aren't currently running, remove from the list
    00473   // this includes all finished or cancelled requests
    00474
    00475   if (curr->worker->m_finished && curr->nRequests == 0)
    00476     {
    00477       // this one has finished
    00478       if (curr->obj)
    00479     curr->obj->status = KResolver::PostProcessing; // post-processing is run in doNotifying()
    00480
    00481       if (curr->requestor)
    00482     --curr->requestor->nRequests;
    00483
    00484       //qDebug("KResolverManager::handleFinishedItem(%u): removing %p since it's done",
    00485     //     pid, (void*)curr);
    00486       return true;
    00487     }
    00488   return false;
    00489 }
    00490
    00491
    00492
    00493 void KResolverManager::registerNewWorker(KResolverWorkerFactoryBase *factory)
    00494 {
    00495   workerFactories.append(factory);
    00496 }
    00497
    00498 KResolverWorkerBase* KResolverManager::findWorker(KResolverPrivate* p)
    00499 {
    00501   // this function can be called on any user thread
    00503
    00504   // this function is called with an unlocked mutex and it's expected to be
    00505   // thread-safe!
    00506   // but the factory list is expected not to be changed asynchronously
    00507
    00508   // This function is responsible for finding a suitable worker for the given
    00509   // input. That means we have to do a costly operation to create each worker
    00510   // class and call their preprocessing functions. The first one that
    00511   // says they can process (i.e., preprocess() returns true) will get the job.
    00512
    00513   KResolverWorkerBase *worker;
    00514   for (KResolverWorkerFactoryBase *factory = workerFactories.first(); factory;
    00515        factory = workerFactories.next())
    00516     {
    00517       worker = factory->create();
    00518
    00519       // set up the data the worker needs to preprocess
    00520       worker->input = &p->input;
    00521
    00522       if (worker->preprocess())
    00523     {
    00524       // good, this one says it can process
    00525       if (worker->m_finished)
    00526         p->status = KResolver::PostProcessing;
    00527       else
    00528         p->status = KResolver::Queued;
    00529       return worker;
    00530     }
    00531
    00532       // no, try again
    00533       delete worker;
    00534     }
    00535
    00536   // found no worker
    00537   return 0L;
    00538 }
    00539
    00540 void KResolverManager::doNotifying(RequestData *p)
    00541 {
    00543   // This function may be called on any thread
    00544   // any thread at all: user threads, GUI thread, manager thread or worker thread
    00546
    00547   // Notification and finalisation
    00548   //
    00549   // Once a request has finished the normal processing, we call the
    00550   // post processing function.
    00551   //
    00552   // After that is done, we will consolidate all results in the object's
    00553   // KResolverResults and then post an event indicating that the signal
    00554   // be emitted
    00555   //
    00556   // In case we detect that the object is waiting for completion, we do not
    00557   // post the event, for KResolver::wait will take care of emitting the
    00558   // signal.
    00559   //
    00560   // Once we release the mutex on the object, we may no longer reference it
    00561   // for it might have been deleted.
    00562
    00563   // "User" objects are those that are not created by the manager. Note that
    00564   // objects created by worker threads are considered "user" objects. Objects
    00565   // created by the manager are those created for KResolver::resolveAsync.
    00566   // We should delete them.
    00567
    00568   if (p->obj)
    00569     {
    00570       // lock the object
    00571       p->obj->mutex.lock();
    00572       KResolver* parent = p->obj->parent; // is 0 for non-"user" objects
    00573       KResolverResults& r = p->obj->results;
    00574
    00575       if (p->obj->status == KResolver::Canceled)
    00576     {
    00577       p->obj->status = KResolver::Canceled;
    00578       p->obj->errorcode = KResolver::Canceled;
    00579       p->obj->syserror = 0;
    00580       r.setError(KResolver::Canceled, 0);
    00581     }
    00582       else if (p->worker)
    00583     {
    00584       // post processing
    00585       p->worker->postprocess(); // ignore the result
    00586
    00587       // copy the results from the worker thread to the final
    00588       // object
    00589       r = p->worker->results;
    00590
    00591       // reset address
    00592       r.setAddress(p->input->node, p->input->service);
    00593
    00594       //qDebug("KResolverManager::doNotifying(%u/%p): for %p whose status is %d and has %d results",
    00595          //pid, (void*)QThread::currentThread(), (void*)p, p->obj->status, r.count());
    00596
    00597       p->obj->errorcode = r.error();
    00598       p->obj->syserror = r.systemError();
    00599       p->obj->status = !r.isEmpty() ?
    00600         KResolver::Success : KResolver::Failed;
    00601     }
    00602       else
    00603     {
    00604       r.empty();
    00605       r.setError(p->obj->errorcode, p->obj->syserror);
    00606     }
    00607
    00608       // check whether there's someone waiting
    00609       if (!p->obj->waiting && parent)
    00610     // no, so we must post an event requesting that the signal be emitted
    00611     // sorry for the C-style cast, but neither static nor reintepret cast work
    00612     // here; I'd have to do two casts
    00613     QApplication::postEvent(parent, new QEvent((QEvent::Type)(ResolutionCompleted)));
    00614
    00615       // release the mutex
    00616       p->obj->mutex.unlock();
    00617     }
    00618   else
    00619     {
    00620       // there's no object!
    00621       if (p->worker)
    00622     p->worker->postprocess();
    00623     }
    00624
    00625   delete p->worker;
    00626
    00627   // ignore p->requestor and p->nRequests
    00628   // they have been dealt with by the main loop
    00629
    00630   delete p;
    00631
    00632   // notify any objects waiting in KResolver::wait
    00633   notifyWaiters.wakeAll();
    00634 }
    00635
    00636 // enqueue a new request
    00637 // this function is called from KResolver::start and
    00638 // from KResolverWorkerBase::enqueue
    00639 void KResolverManager::enqueue(KResolver *obj, RequestData *requestor)
    00640 {
    00641   RequestData *newrequest = new RequestData;
    00642   newrequest->nRequests = 0;
    00643   newrequest->obj = obj->d;
    00644   newrequest->input = &obj->d->input;
    00645   newrequest->requestor = requestor;
    00646
    00647   // when processing a new request, find the most
    00648   // suitable worker
    00649   if ((newrequest->worker = findWorker(obj->d)) == 0L)
    00650     {
    00651       // oops, problem
    00652       // cannot find a worker class for this guy
    00653       obj->d->status = KResolver::Failed;
    00654       obj->d->errorcode = KResolver::UnsupportedFamily;
    00655       obj->d->syserror = 0;
    00656
    00657       doNotifying(newrequest);
    00658       return;
    00659     }
    00660
    00661   // no, queue it
    00662   // p->status was set in findWorker!
    00663   if (requestor)
    00664     requestor->nRequests++;
    00665
    00666   if (!newrequest->worker->m_finished)
    00667     dispatch(newrequest);
    00668   else if (newrequest->nRequests > 0)
    00669     {
    00670       mutex.lock();
    00671       currentRequests.append(newrequest);
    00672       mutex.unlock();
    00673     }
    00674   else
    00675     // already done
    00676     doNotifying(newrequest);
    00677 }
    00678
    00679 // a new request has been created
    00680 // dispatch it
    00681 void KResolverManager::dispatch(RequestData *data)
    00682 {
    00683   // As stated in the beginning of the file, this function
    00684   // is supposed to verify the availability of threads, start
    00685   // any if necessary
    00686
    00687   QMutexLocker locker(&mutex);
    00688
    00689   // add to the queue
    00690   newRequests.append(data);
    00691
    00692   // check if we need to start a new thread
    00693   //
    00694   // we depend on the variables availableThreads and runningThreads to
    00695   // know if we are supposed to start any threads:
    00696   // - if availableThreads > 0, then there is at least one thread waiting,
    00697   //    blocked in KResolverManager::requestData. It can't unblock
    00698   //    while we are holding the mutex locked, therefore we are sure that
    00699   //    our event will be handled
    00700   // - if availableThreads == 0:
    00701   //   - if runningThreads < maxThreads
    00702   //     we will start a new thread, which will certainly block in
    00703   //     KResolverManager::requestData because we are holding the mutex locked
    00704   //   - if runningThreads == maxThreads
    00705   //     This situation generally means that we have already maxThreads running
    00706   //     and that all of them are processing. We will not start any new threads,
    00707   //     but will instead wait for one to finish processing and request new data
    00708   //
    00709   //     There's a possible race condition here, which goes unhandled: if one of
    00710   //     threads has timed out waiting for new data and is in the process of
    00711   //     exiting. In that case, availableThreads == 0 and runningThreads will not
    00712   //     have decremented yet. This means that we will not start a new thread
    00713   //     that we could have. However, since there are other threads working, our
    00714   //     event should be handled soon.
    00715   //     It won't be handled if and only if ALL threads are in the process of
    00716   //     exiting. That situation is EXTREMELY unlikely and is not handled either.
    00717   //
    00718   if (availableThreads == 0 && runningThreads < maxThreads)
    00719     {
    00720       // yes, a new thread should be started
    00721
    00722       // find if there's a finished one
    00723       KResolverThread *th = workers.first();
    00724       while (th && th->running())
    00725     th = workers.next();
    00726
    00727       if (th == 0L)
    00728     // no, create one
    00729     th = new KResolverThread;
    00730       else
    00731     workers.take();
    00732
    00733       th->start();
    00734       workers.append(th);
    00735       runningThreads++;
    00736     }
    00737
    00738   feedWorkers.wakeAll();
    00739
    00740   // clean up idle threads
    00741   workers.first();
    00742   while (workers.current())
    00743     {
    00744       if (!workers.current()->running())
    00745     workers.remove();
    00746       else
    00747     workers.next();
    00748     }
    00749 }
    00750
    00751 // this function is called by KResolverManager::dequeue
    00752 bool KResolverManager::dequeueNew(KResolver* obj)
    00753 {
    00754   // This function must be called with a locked mutex
    00755   // Deadlock warning:
    00756   // always lock the global mutex first if both mutexes must be locked
    00757
    00758   KResolverPrivate *d = obj->d;
    00759
    00760   // check if it's in the new request list
    00761   RequestData *curr = newRequests.first();
    00762   while (curr)
    00763     if (curr->obj == d)
    00764       {
    00765     // yes, this object is still in the list
    00766     // but it has never been processed
    00767     d->status = KResolver::Canceled;
    00768     d->errorcode = KResolver::Canceled;
    00769     d->syserror = 0;
    00770     newRequests.take();
    00771
    00772     delete curr->worker;
    00773     delete curr;
    00774
    00775     return true;
    00776       }
    00777     else
    00778       curr = newRequests.next();
    00779
    00780   // check if it's running
    00781   curr = currentRequests.first();
    00782   while (curr)
    00783     if (curr->obj == d)
    00784       {
    00785     // it's running. We cannot simply take it out of the list.
    00786     // it will be handled when the thread that is working on it finishes
    00787     d->mutex.lock();
    00788
    00789     d->status = KResolver::Canceled;
    00790     d->errorcode = KResolver::Canceled;
    00791     d->syserror = 0;
    00792
    00793     // disengage from the running threads
    00794     curr->obj = 0L;
    00795     curr->input = 0L;
    00796     if (curr->worker)
    00797       curr->worker->input = 0L;
    00798
    00799     d->mutex.unlock();
    00800       }
    00801     else
    00802       curr = currentRequests.next();
    00803
    00804   return false;
    00805 }
    00806
    00807 // this function is called by KResolver::cancel
    00808 // it's expected to be thread-safe
    00809 void KResolverManager::dequeue(KResolver *obj)
    00810 {
    00811   QMutexLocker locker(&mutex);
    00812   dequeueNew(obj);
    00813 }

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:10 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003