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