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 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 }
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 Sat Jun 11 20:18:10 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003