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