kdecore Library API Documentation

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