kdecore Library API Documentation

kresolvermanager.cpp

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