File indexing completed on 2023-09-24 04:04:38
0001 /* -*- C++ -*- 0002 * Copyright (C) 2003-2005 Thiago Macieira <thiago@kde.org> 0003 * 0004 * 0005 * Permission is hereby granted, free of charge, to any person obtaining 0006 * a copy of this software and associated documentation files (the 0007 * "Software"), to deal in the Software without restriction, including 0008 * without limitation the rights to use, copy, modify, merge, publish, 0009 * distribute, sublicense, and/or sell copies of the Software, and to 0010 * permit persons to whom the Software is furnished to do so, subject to 0011 * the following conditions: 0012 * 0013 * The above copyright notice and this permission notice shall be included 0014 * in all copies or substantial portions of the Software. 0015 * 0016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 0017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 0018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 0019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 0020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 0021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 0022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0023 */ 0024 0025 #include <config-network.h> 0026 0027 #include <sys/types.h> 0028 #include <netinet/in.h> 0029 #include <limits.h> 0030 #include <unistd.h> // only needed for pid_t 0031 0032 #if HAVE_RES_INIT 0033 # include <sys/stat.h> 0034 extern "C" { 0035 # include <arpa/nameser.h> 0036 } 0037 # include <time.h> 0038 # include <resolv.h> 0039 #endif 0040 0041 #include <QByteArray> 0042 #include <QCoreApplication> 0043 #include <QList> 0044 #include <QMutableListIterator> 0045 #include <QMutex> 0046 #include <QQueue> 0047 #include <QSemaphore> 0048 0049 #include <QThread> 0050 #include <QTimer> 0051 #include <QWaitCondition> 0052 0053 #include <kde_file.h> 0054 #include <kdebug.h> 0055 #include "k3resolver.h" 0056 #include "k3resolver_p.h" 0057 #include "k3resolverworkerbase.h" 0058 #include "k3resolverstandardworkers_p.h" 0059 0060 using namespace KNetwork; 0061 using namespace KNetwork::Internal; 0062 0063 /* 0064 * Explanation on how the resolver system works 0065 0066 When KResolver::start is called, it calls KResolverManager::enqueue to add 0067 an entry to the queue. KResolverManager::enqueue will verify the availability 0068 of a worker thread: if one is available, it will dispatch the request to it. 0069 If no threads are available, it will then decide whether to launch a thread 0070 or to queue for the future. 0071 0072 (This process is achieved by always queuing the new request, starting a 0073 new thread if necessary and then notifying of the availability of data 0074 to all worker threads). 0075 0076 * Worker thread 0077 A new thread, when started, will enter its event loop 0078 immediately. That is, it'll first try to acquire new data to 0079 process, which means it will lock and unlock the manager mutex in 0080 the process. 0081 0082 If it finds no new data, it'll wait on the feedWorkers condition 0083 for a certain maximum time. If that time expires and there's still 0084 no data, the thread will exit, in order to save system resources. 0085 0086 If it finds data, however, it'll set up and call the worker class 0087 that has been selected by the manager. Once that worker is done, 0088 the thread releases the data through KResolverManager::releaseData. 0089 0090 * Data requesting/releasing 0091 A worker thread always calls upon functions on the resolver manager 0092 in order to acquire and release data. 0093 0094 When data is being requested, the KResolverManager::requestData 0095 function will look the currentRequests list and return the first 0096 Queued request it finds, while marking it to be InProgress. 0097 0098 When the worker class has returned, the worker thread will release 0099 that data through the KResolverManager::releaseData function. If the 0100 worker class has requested no further data (nRequests == 0), the 0101 request's status is marked to be Done. It'll then look at the 0102 requestor for that data: if it was requested by another worker, 0103 it'll decrement the requests count for that one and add the results 0104 to a list. And, finally, if the requests count for the requestor 0105 becomes 0, it'll repeat this process for the requestor as well 0106 (change status to Done, check for a requestor). 0107 */ 0108 0109 namespace 0110 { 0111 0112 /* 0113 * This class is used to control the access to the 0114 * system's resolver API. 0115 * 0116 * It is necessary to periodically poll /etc/resolv.conf and reload 0117 * it if any changes are noticed. This class does exactly that. 0118 * 0119 * However, there's also the problem of reloading the structure while 0120 * some threads are in progress. Therefore, we keep a usage reference count. 0121 */ 0122 class ResInitUsage 0123 { 0124 public: 0125 0126 #if HAVE_RES_INIT 0127 time_t mTime; 0128 int useCount; 0129 0130 # ifndef RES_INIT_THREADSAFE 0131 QWaitCondition cond; 0132 QMutex mutex; 0133 # endif 0134 0135 bool shouldResInit() 0136 { 0137 // check if /etc/resolv.conf has changed 0138 KDE_struct_stat st; 0139 if (KDE_stat("/etc/resolv.conf", &st) != 0) { 0140 return false; 0141 } 0142 0143 if (mTime != st.st_mtime) { 0144 kDebug(179) << "shouldResInit: /etc/resolv.conf updated"; 0145 return true; 0146 } 0147 return false; 0148 } 0149 0150 void callResInit() 0151 { 0152 if (mTime != 0) { 0153 // don't call it the first time 0154 // let it be initialized naturally 0155 kDebug(179) << "callResInit: calling res_init()"; 0156 res_init(); 0157 } 0158 0159 KDE_struct_stat st; 0160 if (KDE_stat("/etc/resolv.conf", &st) == 0) { 0161 mTime = st.st_mtime; 0162 } 0163 } 0164 0165 ResInitUsage() 0166 : mTime(0), useCount(0) 0167 { } 0168 0169 /* 0170 * Marks the end of usage to the resolver tools 0171 */ 0172 void release() 0173 { 0174 # ifndef RES_INIT_THREADSAFE 0175 QMutexLocker locker(&mutex); 0176 if (--useCount == 0) { 0177 if (shouldResInit()) { 0178 callResInit(); 0179 } 0180 0181 // we've reached 0, wake up anyone that's waiting to call res_init 0182 cond.wakeAll(); 0183 } 0184 # else 0185 // do nothing 0186 # endif 0187 } 0188 0189 /* 0190 * Marks the beginning of usage of the resolver API 0191 */ 0192 void acquire() 0193 { 0194 # ifndef RES_INIT_THREADSAFE 0195 mutex.lock(); 0196 0197 if (shouldResInit()) { 0198 if (useCount) { 0199 // other threads are already using the API, so wait till 0200 // it's all clear 0201 // the thread that emits this condition will also call res_init 0202 //qDebug("ResInitUsage: waiting for libresolv to be clear"); 0203 cond.wait(&mutex); 0204 } else 0205 // we're clear 0206 { 0207 callResInit(); 0208 } 0209 } 0210 useCount++; 0211 mutex.unlock(); 0212 0213 # else 0214 if (shouldResInit()) { 0215 callResInit(); 0216 } 0217 0218 # endif 0219 } 0220 0221 #else 0222 ResInitUsage() 0223 { } 0224 0225 bool shouldResInit() 0226 { 0227 return false; 0228 } 0229 0230 void acquire() 0231 { } 0232 0233 void release() 0234 { } 0235 #endif 0236 0237 } resInit; 0238 0239 } // anonymous namespace 0240 0241 /* 0242 * parameters 0243 */ 0244 // a thread will try maxThreadRetries to get data, waiting at most 0245 // maxThreadWaitTime milliseconds between each attempt. After that, it'll 0246 // exit 0247 static const int maxThreadWaitTime = 2000; // 2 seconds 0248 static const int maxThreads = 5; 0249 0250 static pid_t pid; // FIXME -- disable when everything is ok 0251 0252 KResolverThread::KResolverThread() 0253 : data(nullptr) 0254 { 0255 } 0256 0257 // remember! This function runs in a separate thread! 0258 void KResolverThread::run() 0259 { 0260 // initialization 0261 // enter the loop already 0262 0263 //qDebug("KResolverThread(thread %u/%p): started", pid, (void*)QThread::currentThread()); 0264 KResolverManager::manager()->registerThread(this); 0265 while (true) { 0266 data = KResolverManager::manager()->requestData(this, ::maxThreadWaitTime); 0267 //qDebug("KResolverThread(thread %u/%p) got data %p", KResolverManager::pid, 0268 // (void*)QThread::currentThread(), (void*)data); 0269 if (data) { 0270 // yes, we got data 0271 // process it! 0272 0273 // 1) set up 0274 ; 0275 0276 // 2) run it 0277 data->worker->run(); 0278 0279 // 3) release data 0280 KResolverManager::manager()->releaseData(this, data); 0281 0282 // now go back to the loop 0283 } else { 0284 break; 0285 } 0286 } 0287 0288 KResolverManager::manager()->unregisterThread(this); 0289 //qDebug("KResolverThread(thread %u/%p): exiting", pid, (void*)QThread::currentThread()); 0290 } 0291 0292 bool KResolverThread::checkResolver() 0293 { 0294 return resInit.shouldResInit(); 0295 } 0296 0297 void KResolverThread::acquireResolver() 0298 { 0299 #if defined(NEED_MUTEX) && !defined(Q_OS_FREEBSD) 0300 getXXbyYYmutex.lock(); 0301 #endif 0302 0303 resInit.acquire(); 0304 } 0305 0306 void KResolverThread::releaseResolver() 0307 { 0308 #if defined(NEED_MUTEX) && !defined(Q_OS_FREEBSD) 0309 getXXbyYYmutex.unlock(); 0310 #endif 0311 0312 resInit.release(); 0313 } 0314 0315 static KResolverManager *globalManager; 0316 0317 KResolverManager *KResolverManager::manager() 0318 { 0319 if (globalManager == nullptr) { 0320 new KResolverManager(); 0321 } 0322 return globalManager; 0323 } 0324 0325 KResolverManager::KResolverManager() 0326 : runningThreads(0), availableThreads(0) 0327 { 0328 globalManager = this; 0329 initStandardWorkers(); 0330 0331 pid = getpid(); 0332 } 0333 0334 KResolverManager::~KResolverManager() 0335 { 0336 // this should never be called 0337 0338 // kill off running threads 0339 foreach (KResolverThread *worker, workers) { 0340 worker->terminate(); 0341 } 0342 } 0343 0344 void KResolverManager::registerThread(KResolverThread *) 0345 { 0346 } 0347 0348 void KResolverManager::unregisterThread(KResolverThread *) 0349 { 0350 runningThreads--; 0351 } 0352 0353 // this function is called by KResolverThread::run 0354 RequestData *KResolverManager::requestData(KResolverThread *th, int maxWaitTime) 0355 { 0356 ///// 0357 // This function is called in a worker thread!! 0358 ///// 0359 0360 // lock the mutex, so that the manager thread or other threads won't 0361 // interfere. 0362 QMutexLocker locker(&mutex); 0363 RequestData *data = findData(th); 0364 0365 if (data) 0366 // it found something, that's good 0367 { 0368 return data; 0369 } 0370 0371 // nope, nothing found; sleep for a while 0372 availableThreads++; 0373 feedWorkers.wait(&mutex, maxWaitTime); 0374 availableThreads--; 0375 0376 data = findData(th); 0377 return data; 0378 } 0379 0380 RequestData *KResolverManager::findData(KResolverThread *th) 0381 { 0382 ///// 0383 // This function is called by requestData() above and must 0384 // always be called with a locked mutex 0385 ///// 0386 0387 // now find data to be processed 0388 QMutableListIterator<RequestData *> it(newRequests); 0389 while (it.hasNext()) { 0390 RequestData *curr = it.next(); 0391 if (!curr->worker->m_finished) { 0392 // found one 0393 if (curr->obj) { 0394 curr->obj->status = KResolver::InProgress; 0395 } 0396 curr->worker->th = th; 0397 0398 // move it to the currentRequests list 0399 it.remove(); 0400 currentRequests.append(curr); 0401 0402 return curr; 0403 } 0404 } 0405 0406 // found nothing! 0407 return nullptr; 0408 } 0409 0410 // this function is called by KResolverThread::run 0411 void KResolverManager::releaseData(KResolverThread *, RequestData *data) 0412 { 0413 ///// 0414 // This function is called in a worker thread!! 0415 ///// 0416 0417 //qDebug("KResolverManager::releaseData(%u/%p): %p has been released", pid, 0418 // (void*)QThread::currentThread(), (void*)data); 0419 0420 if (data->obj) { 0421 data->obj->status = KResolver::PostProcessing; 0422 } 0423 0424 data->worker->m_finished = true; 0425 data->worker->th = nullptr; // this releases the object 0426 0427 // handle finished requests 0428 handleFinished(); 0429 } 0430 0431 // this function is called by KResolverManager::releaseData above 0432 void KResolverManager::handleFinished() 0433 { 0434 bool redo = false; 0435 QQueue<RequestData *> doneRequests; 0436 0437 mutex.lock(); 0438 if (currentRequests.isEmpty()) { 0439 mutex.unlock(); 0440 return; 0441 } 0442 0443 // loop over all items on the currently running list 0444 // we loop from the last to the first so that we catch requests 0445 // with "requestors" before we catch the requestor itself. 0446 QMutableListIterator<RequestData *> it(currentRequests); 0447 it.toBack(); 0448 while (it.hasPrevious()) { 0449 RequestData *curr = it.previous(); 0450 if (curr->worker->th == nullptr) { 0451 if (handleFinishedItem(curr)) { 0452 it.remove(); 0453 doneRequests.enqueue(curr); 0454 0455 if (curr->requestor && 0456 curr->requestor->nRequests == 0 && 0457 curr->requestor->worker->m_finished) 0458 // there's a requestor that is now finished 0459 { 0460 redo = true; 0461 } 0462 } 0463 } 0464 } 0465 0466 //qDebug("KResolverManager::handleFinished(%u): %d requests to notify", pid, doneRequests.count()); 0467 while (!doneRequests.isEmpty()) { 0468 doNotifying(doneRequests.dequeue()); 0469 } 0470 0471 mutex.unlock(); 0472 0473 if (redo) { 0474 //qDebug("KResolverManager::handleFinished(%u): restarting processing to catch requestor", 0475 // pid); 0476 handleFinished(); 0477 } 0478 } 0479 0480 // This function is called by KResolverManager::handleFinished above 0481 bool KResolverManager::handleFinishedItem(RequestData *curr) 0482 0483 { 0484 // for all items that aren't currently running, remove from the list 0485 // this includes all finished or canceled requests 0486 0487 if (curr->worker->m_finished && curr->nRequests == 0) { 0488 // this one has finished 0489 if (curr->obj) { 0490 curr->obj->status = KResolver::PostProcessing; // post-processing is run in doNotifying() 0491 } 0492 0493 if (curr->requestor) { 0494 --curr->requestor->nRequests; 0495 } 0496 0497 //qDebug("KResolverManager::handleFinishedItem(%u): removing %p since it's done", 0498 // pid, (void*)curr); 0499 return true; 0500 } 0501 return false; 0502 } 0503 0504 void KResolverManager::registerNewWorker(KResolverWorkerFactoryBase *factory) 0505 { 0506 workerFactories.append(factory); 0507 } 0508 0509 KResolverWorkerBase *KResolverManager::findWorker(KResolverPrivate *p) 0510 { 0511 ///// 0512 // this function can be called on any user thread 0513 ///// 0514 0515 // this function is called with an unlocked mutex and it's expected to be 0516 // thread-safe! 0517 // but the factory list is expected not to be changed asynchronously 0518 0519 // This function is responsible for finding a suitable worker for the given 0520 // input. That means we have to do a costly operation to create each worker 0521 // class and call their preprocessing functions. The first one that 0522 // says they can process (i.e., preprocess() returns true) will get the job. 0523 0524 foreach (KResolverWorkerFactoryBase *factory, workerFactories) { 0525 KResolverWorkerBase *worker = factory->create(); 0526 0527 // set up the data the worker needs to preprocess 0528 worker->input = &p->input; 0529 0530 if (worker->preprocess()) { 0531 // good, this one says it can process 0532 if (worker->m_finished) { 0533 p->status = KResolver::PostProcessing; 0534 } else { 0535 p->status = KResolver::Queued; 0536 } 0537 return worker; 0538 } 0539 0540 // no, try again 0541 delete worker; 0542 } 0543 0544 // found no worker 0545 return nullptr; 0546 } 0547 0548 void KResolverManager::doNotifying(RequestData *p) 0549 { 0550 ///// 0551 // This function may be called on any thread 0552 // any thread at all: user threads, GUI thread, manager thread or worker thread 0553 ///// 0554 0555 // Notification and finalisation 0556 // 0557 // Once a request has finished the normal processing, we call the 0558 // post processing function. 0559 // 0560 // After that is done, we will consolidate all results in the object's 0561 // KResolverResults and then post an event indicating that the signal 0562 // be emitted 0563 // 0564 // In case we detect that the object is waiting for completion, we do not 0565 // post the event, for KResolver::wait will take care of emitting the 0566 // signal. 0567 // 0568 // Once we release the mutex on the object, we may no longer reference it 0569 // for it might have been deleted. 0570 0571 // "User" objects are those that are not created by the manager. Note that 0572 // objects created by worker threads are considered "user" objects. Objects 0573 // created by the manager are those created for KResolver::resolveAsync. 0574 // We should delete them. 0575 0576 if (p->obj) { 0577 // lock the object 0578 p->obj->mutex.lock(); 0579 KResolver *parent = p->obj->parent; // is 0 for non-"user" objects 0580 KResolverResults &r = p->obj->results; 0581 0582 if (p->obj->status == KResolver::Canceled) { 0583 p->obj->status = KResolver::Canceled; 0584 p->obj->errorcode = KResolver::Canceled; 0585 p->obj->syserror = 0; 0586 r.setError(KResolver::Canceled, 0); 0587 } else if (p->worker) { 0588 // post processing 0589 p->worker->postprocess(); // ignore the result 0590 0591 // copy the results from the worker thread to the final 0592 // object 0593 r = p->worker->results; 0594 0595 // reset address 0596 r.setAddress(p->input->node, p->input->service); 0597 0598 //qDebug("KResolverManager::doNotifying(%u/%p): for %p whose status is %d and has %d results", 0599 //pid, (void*)QThread::currentThread(), (void*)p, p->obj->status, r.count()); 0600 0601 p->obj->errorcode = r.error(); 0602 p->obj->syserror = r.systemError(); 0603 p->obj->status = !r.isEmpty() ? 0604 KResolver::Success : KResolver::Failed; 0605 } else { 0606 r.clear(); 0607 r.setError(p->obj->errorcode, p->obj->syserror); 0608 } 0609 0610 // check whether there's someone waiting 0611 if (!p->obj->waiting && parent) 0612 // no, so we must post an event requesting that the signal be emitted 0613 // sorry for the C-style cast, but neither static nor reintepret cast work 0614 // here; I'd have to do two casts 0615 { 0616 QCoreApplication::postEvent(parent, new QEvent((QEvent::Type)(ResolutionCompleted))); 0617 } 0618 0619 // release the mutex 0620 p->obj->mutex.unlock(); 0621 } else { 0622 // there's no object! 0623 if (p->worker) { 0624 p->worker->postprocess(); 0625 } 0626 } 0627 0628 delete p->worker; 0629 0630 // ignore p->requestor and p->nRequests 0631 // they have been dealt with by the main loop 0632 0633 delete p; 0634 0635 // notify any objects waiting in KResolver::wait 0636 notifyWaiters.wakeAll(); 0637 } 0638 0639 // enqueue a new request 0640 // this function is called from KResolver::start and 0641 // from KResolverWorkerBase::enqueue 0642 void KResolverManager::enqueue(KResolver *obj, RequestData *requestor) 0643 { 0644 RequestData *newrequest = new RequestData; 0645 newrequest->nRequests = 0; 0646 newrequest->obj = obj->d; 0647 newrequest->input = &obj->d->input; 0648 newrequest->requestor = requestor; 0649 0650 // when processing a new request, find the most 0651 // suitable worker 0652 if ((newrequest->worker = findWorker(obj->d)) == nullptr) { 0653 // oops, problem 0654 // cannot find a worker class for this guy 0655 obj->d->status = KResolver::Failed; 0656 obj->d->errorcode = KResolver::UnsupportedFamily; 0657 obj->d->syserror = 0; 0658 0659 doNotifying(newrequest); 0660 return; 0661 } 0662 0663 // no, queue it 0664 // p->status was set in findWorker! 0665 if (requestor) { 0666 requestor->nRequests++; 0667 } 0668 0669 if (!newrequest->worker->m_finished) { 0670 dispatch(newrequest); 0671 } else if (newrequest->nRequests > 0) { 0672 mutex.lock(); 0673 currentRequests.append(newrequest); 0674 mutex.unlock(); 0675 } else 0676 // already done 0677 { 0678 doNotifying(newrequest); 0679 } 0680 } 0681 0682 // a new request has been created 0683 // dispatch it 0684 void KResolverManager::dispatch(RequestData *data) 0685 { 0686 // As stated in the beginning of the file, this function 0687 // is supposed to verify the availability of threads, start 0688 // any if necessary 0689 0690 QMutexLocker locker(&mutex); 0691 0692 // add to the queue 0693 newRequests.append(data); 0694 0695 // check if we need to start a new thread 0696 // 0697 // we depend on the variables availableThreads and runningThreads to 0698 // know if we are supposed to start any threads: 0699 // - if availableThreads > 0, then there is at least one thread waiting, 0700 // blocked in KResolverManager::requestData. It can't unblock 0701 // while we are holding the mutex locked, therefore we are sure that 0702 // our event will be handled 0703 // - if availableThreads == 0: 0704 // - if runningThreads < maxThreads 0705 // we will start a new thread, which will certainly block in 0706 // KResolverManager::requestData because we are holding the mutex locked 0707 // - if runningThreads == maxThreads 0708 // This situation generally means that we have already maxThreads running 0709 // and that all of them are processing. We will not start any new threads, 0710 // but will instead wait for one to finish processing and request new data 0711 // 0712 // There's a possible race condition here, which goes unhandled: if one of 0713 // threads has timed out waiting for new data and is in the process of 0714 // exiting. In that case, availableThreads == 0 and runningThreads will not 0715 // have decremented yet. This means that we will not start a new thread 0716 // that we could have. However, since there are other threads working, our 0717 // event should be handled soon. 0718 // It won't be handled if and only if ALL threads are in the process of 0719 // exiting. That situation is EXTREMELY unlikely and is not handled either. 0720 // 0721 if (availableThreads == 0 && runningThreads < maxThreads) { 0722 // yes, a new thread should be started 0723 0724 // find if there's a finished one 0725 KResolverThread *th = nullptr; 0726 for (int i = 0; i < workers.size(); ++i) 0727 if (!workers[i]->isRunning()) { 0728 th = workers[i]; 0729 break; 0730 } 0731 0732 if (th == nullptr) { 0733 // no, create one 0734 th = new KResolverThread; 0735 workers.append(th); 0736 } 0737 0738 th->start(); 0739 runningThreads++; 0740 } 0741 0742 feedWorkers.wakeAll(); 0743 0744 // clean up idle threads 0745 QMutableListIterator<KResolverThread *> it(workers); 0746 while (it.hasNext()) { 0747 KResolverThread *worker = it.next(); 0748 if (!worker->isRunning()) { 0749 it.remove(); 0750 delete worker; 0751 } 0752 } 0753 } 0754 0755 // this function is called by KResolverManager::dequeue 0756 bool KResolverManager::dequeueNew(KResolver *obj) 0757 { 0758 // This function must be called with a locked mutex 0759 // Deadlock warning: 0760 // always lock the global mutex first if both mutexes must be locked 0761 0762 KResolverPrivate *d = obj->d; 0763 0764 // check if it's in the new request list 0765 for (QMutableListIterator<RequestData *> it(newRequests); 0766 it.hasNext();) { 0767 RequestData *curr = it.next(); 0768 if (curr->obj == d) { 0769 // yes, this object is still in the list 0770 // but it has never been processed 0771 d->status = KResolver::Canceled; 0772 d->errorcode = KResolver::Canceled; 0773 d->syserror = 0; 0774 it.remove(); 0775 0776 delete curr->worker; 0777 delete curr; 0778 0779 return true; 0780 } 0781 } 0782 0783 // check if it's running 0784 for (int i = 0; i < currentRequests.size(); ++i) { 0785 RequestData *curr = currentRequests[i]; 0786 if (curr->obj == d) { 0787 // it's running. We cannot simply take it out of the list. 0788 // it will be handled when the thread that is working on it finishes 0789 d->mutex.lock(); 0790 0791 d->status = KResolver::Canceled; 0792 d->errorcode = KResolver::Canceled; 0793 d->syserror = 0; 0794 0795 // disengage from the running threads 0796 curr->obj = nullptr; 0797 curr->input = nullptr; 0798 if (curr->worker) { 0799 curr->worker->input = nullptr; 0800 } 0801 0802 d->mutex.unlock(); 0803 } 0804 } 0805 0806 return false; 0807 } 0808 0809 // this function is called by KResolver::cancel 0810 // it's expected to be thread-safe 0811 void KResolverManager::dequeue(KResolver *obj) 0812 { 0813 QMutexLocker locker(&mutex); 0814 dequeueNew(obj); 0815 }