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       data->obj->status = KResolver::PostProcessing;    
00416     }
00417       
00418   data->worker->m_finished = true;
00419   data->worker->th = 0L;    // this releases the object
00420 
00421   // handle finished requests
00422   handleFinished();
00423 }
00424 
00425 // this function is called by KResolverManager::releaseData above
00426 void KResolverManager::handleFinished()
00427 {  
00428   bool redo = false;
00429   QPtrQueue<RequestData> doneRequests;
00430 
00431   mutex.lock();
00432 
00433   // loop over all items on the currently running list
00434   // we loop from the last to the first so that we catch requests with "requestors" before
00435   // we catch the requestor itself.
00436   RequestData *curr = currentRequests.last();
00437   while (curr)
00438     {
00439       if (curr->worker->th == 0L)
00440     {
00441       if (handleFinishedItem(curr))
00442         {
00443           doneRequests.enqueue(currentRequests.take());
00444           if (curr->requestor &&
00445           curr->requestor->nRequests == 0 && 
00446           curr->requestor->worker->m_finished)
00447         // there's a requestor that is now finished
00448         redo = true;
00449         }
00450     }
00451       
00452       curr = currentRequests.prev();
00453     }
00454       
00455   //qDebug("KResolverManager::handleFinished(%u): %d requests to notify", pid, doneRequests.count());
00456   while (RequestData *d = doneRequests.dequeue())
00457     doNotifying(d);
00458 
00459   mutex.unlock();
00460 
00461   if (redo)
00462     {
00463       //qDebug("KResolverManager::handleFinished(%u): restarting processing to catch requestor",
00464     //     pid);
00465       handleFinished();
00466     }
00467 }
00468 
00469 // This function is called by KResolverManager::handleFinished above
00470 bool KResolverManager::handleFinishedItem(RequestData* curr)
00471                       
00472 {
00473   // for all items that aren't currently running, remove from the list
00474   // this includes all finished or cancelled requests
00475 
00476   if (curr->worker->m_finished && curr->nRequests == 0)
00477     {
00478       // this one has finished
00479       if (curr->obj)
00480     curr->obj->status = KResolver::PostProcessing; // post-processing is run in doNotifying()
00481 
00482       if (curr->requestor)
00483     --curr->requestor->nRequests;
00484 
00485       //qDebug("KResolverManager::handleFinishedItem(%u): removing %p since it's done",
00486     //     pid, (void*)curr);
00487       return true;
00488     }
00489   return false;
00490 }
00491 
00492 
00493 
00494 void KResolverManager::registerNewWorker(KResolverWorkerFactoryBase *factory)
00495 {
00496   workerFactories.append(factory);
00497 }
00498 
00499 KResolverWorkerBase* KResolverManager::findWorker(KResolverPrivate* p)
00500 {
00502   // this function can be called on any user thread
00504 
00505   // this function is called with an unlocked mutex and it's expected to be 
00506   // thread-safe!
00507   // but the factory list is expected not to be changed asynchronously
00508 
00509   // This function is responsible for finding a suitable worker for the given
00510   // input. That means we have to do a costly operation to create each worker
00511   // class and call their preprocessing functions. The first one that
00512   // says they can process (i.e., preprocess() returns true) will get the job.
00513 
00514   KResolverWorkerBase *worker;
00515   for (KResolverWorkerFactoryBase *factory = workerFactories.first(); factory; 
00516        factory = workerFactories.next())
00517     {
00518       worker = factory->create();
00519 
00520       // set up the data the worker needs to preprocess
00521       worker->input = &p->input;
00522 
00523       if (worker->preprocess())
00524     {
00525       // good, this one says it can process
00526       if (worker->m_finished)      
00527         p->status = KResolver::PostProcessing;
00528       else
00529         p->status = KResolver::Queued;
00530       return worker;
00531     }
00532 
00533       // no, try again
00534       delete worker;
00535     }
00536 
00537   // found no worker
00538   return 0L;
00539 }
00540 
00541 void KResolverManager::doNotifying(RequestData *p)
00542 {
00544   // This function may be called on any thread
00545   // any thread at all: user threads, GUI thread, manager thread or worker thread
00547 
00548   // Notification and finalisation
00549   //
00550   // Once a request has finished the normal processing, we call the
00551   // post processing function.
00552   //
00553   // After that is done, we will consolidate all results in the object's
00554   // KResolverResults and then post an event indicating that the signal
00555   // be emitted
00556   //
00557   // In case we detect that the object is waiting for completion, we do not
00558   // post the event, for KResolver::wait will take care of emitting the
00559   // signal.
00560   //
00561   // Once we release the mutex on the object, we may no longer reference it
00562   // for it might have been deleted.
00563 
00564   // "User" objects are those that are not created by the manager. Note that
00565   // objects created by worker threads are considered "user" objects. Objects
00566   // created by the manager are those created for KResolver::resolveAsync.
00567   // We should delete them.
00568 
00569   if (p->obj)
00570     {
00571       // lock the object
00572       p->obj->mutex.lock();
00573       KResolver* parent = p->obj->parent; // is 0 for non-"user" objects
00574       KResolverResults& r = p->obj->results;
00575 
00576       if (p->obj->status == KResolver::Canceled)
00577     {
00578       p->obj->status = KResolver::Canceled;
00579       p->obj->errorcode = KResolver::Canceled;
00580       p->obj->syserror = 0;
00581       r.setError(KResolver::Canceled, 0);
00582     }
00583       else if (p->worker)
00584     {
00585       // post processing
00586       p->worker->postprocess(); // ignore the result
00587 
00588       // copy the results from the worker thread to the final
00589       // object
00590       r = p->worker->results;
00591 
00592       // reset address
00593       r.setAddress(p->input->node, p->input->service);
00594 
00595       //qDebug("KResolverManager::doNotifying(%u/%p): for %p whose status is %d and has %d results", 
00596          //pid, (void*)QThread::currentThread(), (void*)p, p->obj->status, r.count());
00597 
00598       p->obj->errorcode = r.error();
00599       p->obj->syserror = r.systemError();
00600       p->obj->status = !r.isEmpty() ? 
00601         KResolver::Success : KResolver::Failed;
00602     }
00603       else
00604     {
00605       r.empty();
00606       r.setError(p->obj->errorcode, p->obj->syserror);
00607     }
00608 
00609       // check whether there's someone waiting
00610       if (!p->obj->waiting && parent)
00611     // no, so we must post an event requesting that the signal be emitted
00612     // sorry for the C-style cast, but neither static nor reintepret cast work
00613     // here; I'd have to do two casts
00614     QApplication::postEvent(parent, new QEvent((QEvent::Type)(ResolutionCompleted)));
00615 
00616       // release the mutex
00617       p->obj->mutex.unlock();
00618     }
00619   else
00620     {
00621       // there's no object!
00622       if (p->worker)
00623     p->worker->postprocess();
00624     }
00625 
00626   delete p->worker;
00627 
00628   // ignore p->requestor and p->nRequests
00629   // they have been dealt with by the main loop
00630 
00631   delete p;
00632 
00633   // notify any objects waiting in KResolver::wait
00634   notifyWaiters.wakeAll();
00635 }
00636 
00637 // enqueue a new request
00638 // this function is called from KResolver::start and 
00639 // from KResolverWorkerBase::enqueue
00640 void KResolverManager::enqueue(KResolver *obj, RequestData *requestor)
00641 {
00642   RequestData *newrequest = new RequestData;
00643   newrequest->nRequests = 0;
00644   newrequest->obj = obj->d;
00645   newrequest->input = &obj->d->input;
00646   newrequest->requestor = requestor;
00647 
00648   // when processing a new request, find the most
00649   // suitable worker
00650   if ((newrequest->worker = findWorker(obj->d)) == 0L)
00651     {
00652       // oops, problem
00653       // cannot find a worker class for this guy
00654       obj->d->status = KResolver::Failed;
00655       obj->d->errorcode = KResolver::UnsupportedFamily;
00656       obj->d->syserror = 0;
00657 
00658       doNotifying(newrequest);
00659       return;
00660     }
00661 
00662   // no, queue it
00663   // p->status was set in findWorker!
00664   if (requestor)
00665     requestor->nRequests++;
00666 
00667   if (!newrequest->worker->m_finished)
00668     dispatch(newrequest);
00669   else if (newrequest->nRequests > 0)
00670     {
00671       mutex.lock();
00672       currentRequests.append(newrequest);
00673       mutex.unlock();
00674     }
00675   else
00676     // already done
00677     doNotifying(newrequest);
00678 }
00679 
00680 // a new request has been created
00681 // dispatch it
00682 void KResolverManager::dispatch(RequestData *data)
00683 {
00684   // As stated in the beginning of the file, this function
00685   // is supposed to verify the availability of threads, start
00686   // any if necessary
00687 
00688   QMutexLocker locker(&mutex);
00689 
00690   // add to the queue
00691   newRequests.append(data);
00692 
00693   // check if we need to start a new thread
00694   //
00695   // we depend on the variables availableThreads and runningThreads to
00696   // know if we are supposed to start any threads:
00697   // - if availableThreads > 0, then there is at least one thread waiting,
00698   //    blocked in KResolverManager::requestData. It can't unblock
00699   //    while we are holding the mutex locked, therefore we are sure that
00700   //    our event will be handled
00701   // - if availableThreads == 0:
00702   //   - if runningThreads < maxThreads
00703   //     we will start a new thread, which will certainly block in
00704   //     KResolverManager::requestData because we are holding the mutex locked
00705   //   - if runningThreads == maxThreads
00706   //     This situation generally means that we have already maxThreads running
00707   //     and that all of them are processing. We will not start any new threads,
00708   //     but will instead wait for one to finish processing and request new data
00709   //
00710   //     There's a possible race condition here, which goes unhandled: if one of
00711   //     threads has timed out waiting for new data and is in the process of
00712   //     exiting. In that case, availableThreads == 0 and runningThreads will not
00713   //     have decremented yet. This means that we will not start a new thread
00714   //     that we could have. However, since there are other threads working, our
00715   //     event should be handled soon.
00716   //     It won't be handled if and only if ALL threads are in the process of 
00717   //     exiting. That situation is EXTREMELY unlikely and is not handled either.
00718   //
00719   if (availableThreads == 0 && runningThreads < maxThreads)
00720     {
00721       // yes, a new thread should be started
00722 
00723       // find if there's a finished one
00724       KResolverThread *th = workers.first();
00725       while (th && th->running())
00726     th = workers.next();
00727 
00728       if (th == 0L)
00729     // no, create one
00730     th = new KResolverThread;
00731       else
00732     workers.take();
00733 
00734       th->start();
00735       workers.append(th);
00736       runningThreads++;
00737     }
00738 
00739   feedWorkers.wakeAll();
00740 
00741   // clean up idle threads
00742   workers.first();
00743   while (workers.current())
00744     {
00745       if (!workers.current()->running())
00746     workers.remove();
00747       else
00748     workers.next();
00749     }
00750 }
00751 
00752 // this function is called by KResolverManager::dequeue
00753 bool KResolverManager::dequeueNew(KResolver* obj)
00754 {
00755   // This function must be called with a locked mutex
00756   // Deadlock warning:
00757   // always lock the global mutex first if both mutexes must be locked
00758 
00759   KResolverPrivate *d = obj->d;
00760 
00761   // check if it's in the new request list
00762   RequestData *curr = newRequests.first(); 
00763   while (curr)
00764     if (curr->obj == d)
00765       {
00766     // yes, this object is still in the list
00767     // but it has never been processed
00768     d->status = KResolver::Canceled;
00769     d->errorcode = KResolver::Canceled;
00770     d->syserror = 0;
00771     newRequests.take();
00772 
00773     delete curr->worker;
00774     delete curr;
00775     
00776     return true;
00777       }
00778     else
00779       curr = newRequests.next();
00780 
00781   // check if it's running
00782   curr = currentRequests.first();
00783   while (curr)
00784     if (curr->obj == d)
00785       {
00786     // it's running. We cannot simply take it out of the list.
00787     // it will be handled when the thread that is working on it finishes
00788     d->mutex.lock();
00789 
00790     d->status = KResolver::Canceled;
00791     d->errorcode = KResolver::Canceled;
00792     d->syserror = 0;
00793 
00794     // disengage from the running threads
00795     curr->obj = 0L;
00796     curr->input = 0L;
00797     if (curr->worker)
00798       curr->worker->input = 0L;
00799 
00800     d->mutex.unlock();
00801       }
00802     else
00803       curr = currentRequests.next();
00804 
00805   return false;
00806 }
00807 
00808 // this function is called by KResolver::cancel
00809 // it's expected to be thread-safe
00810 void KResolverManager::dequeue(KResolver *obj)
00811 {
00812   QMutexLocker locker(&mutex);
00813   dequeueNew(obj);
00814 }
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 Wed May 4 07:11:22 2005 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003