kresolvermanager.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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>
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 <kdebug.h>
00050 #include "kresolver.h"
00051 #include "kresolver_p.h"
00052 #include "kresolverworkerbase.h"
00053 #include "kresolverstandardworkers_p.h"
00054
00055 using namespace KNetwork;
00056 using namespace KNetwork::Internal;
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 namespace
00105 {
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 class ResInitUsage
00118 {
00119 public:
00120
00121 #ifdef HAVE_RES_INIT
00122 time_t mTime;
00123 int useCount;
00124
00125 # ifndef RES_INIT_THREADSAFE
00126 QWaitCondition cond;
00127 QMutex mutex;
00128 # endif
00129
00130 bool shouldResInit()
00131 {
00132
00133 KDE_struct_stat st;
00134 if (KDE_stat("/etc/resolv.conf", &st) != 0)
00135 return false;
00136
00137 if (mTime != st.st_mtime)
00138 {
00139
00140 return true;
00141 }
00142 return false;
00143 }
00144
00145 void callResInit()
00146 {
00147 if (mTime != 0)
00148 {
00149
00150
00151
00152 res_init();
00153 }
00154
00155 KDE_struct_stat st;
00156 if (KDE_stat("/etc/resolv.conf", &st) == 0)
00157 mTime = st.st_mtime;
00158 }
00159
00160 ResInitUsage()
00161 : mTime(0), useCount(0)
00162 { }
00163
00164
00165
00166
00167 void release()
00168 {
00169 # ifndef RES_INIT_THREADSAFE
00170 QMutexLocker locker(&mutex);
00171 if (--useCount == 0)
00172 {
00173 if (shouldResInit())
00174 callResInit();
00175
00176
00177 cond.wakeAll();
00178 }
00179 # else
00180
00181 # endif
00182 }
00183
00184
00185
00186
00187 void acquire()
00188 {
00189 # ifndef RES_INIT_THREADSAFE
00190 mutex.lock();
00191
00192 if (shouldResInit())
00193 {
00194 if (useCount)
00195 {
00196
00197
00198
00199
00200 cond.wait(&mutex);
00201 }
00202 else
00203
00204 callResInit();
00205 }
00206 useCount++;
00207 mutex.unlock();
00208
00209 # else
00210 if (shouldResInit())
00211 callResInit();
00212
00213 # endif
00214 }
00215
00216 #else
00217 ResInitUsage()
00218 { }
00219
00220 bool shouldResInit()
00221 { return false; }
00222
00223 void acquire()
00224 { }
00225
00226 void release()
00227 { }
00228 #endif
00229
00230 } resInit;
00231
00232 }
00233
00234
00235
00236
00237
00238
00239
00240 static const int maxThreadWaitTime = 2000;
00241 static const int maxThreads = 5;
00242
00243 static pid_t pid;
00244
00245 KResolverThread::KResolverThread()
00246 : data(0L)
00247 {
00248 }
00249
00250
00251 void KResolverThread::run()
00252 {
00253
00254
00255
00256
00257 KResolverManager::manager()->registerThread(this);
00258 while (true)
00259 {
00260 data = KResolverManager::manager()->requestData(this, ::maxThreadWaitTime);
00261
00262
00263 if (data)
00264 {
00265
00266
00267
00268
00269 ;
00270
00271
00272 data->worker->run();
00273
00274
00275 KResolverManager::manager()->releaseData(this, data);
00276
00277
00278 }
00279 else
00280 break;
00281 }
00282
00283 KResolverManager::manager()->unregisterThread(this);
00284
00285 }
00286
00287 bool KResolverThread::checkResolver()
00288 {
00289 return resInit.shouldResInit();
00290 }
00291
00292 void KResolverThread::acquireResolver()
00293 {
00294 #if defined(NEED_MUTEX) && !defined(Q_OS_FREEBSD)
00295 getXXbyYYmutex.lock();
00296 #endif
00297
00298 resInit.acquire();
00299 }
00300
00301 void KResolverThread::releaseResolver()
00302 {
00303 #if defined(NEED_MUTEX) && !defined(Q_OS_FREEBSD)
00304 getXXbyYYmutex.unlock();
00305 #endif
00306
00307 resInit.release();
00308 }
00309
00310 static KResolverManager *globalManager;
00311
00312 KResolverManager* KResolverManager::manager()
00313 {
00314 if (globalManager == 0L)
00315 new KResolverManager();
00316 return globalManager;
00317 }
00318
00319 KResolverManager::KResolverManager()
00320 : runningThreads(0), availableThreads(0)
00321 {
00322 globalManager = this;
00323 workers.setAutoDelete(true);
00324 currentRequests.setAutoDelete(true);
00325 initStandardWorkers();
00326
00327 pid = getpid();
00328 }
00329
00330 KResolverManager::~KResolverManager()
00331 {
00332
00333
00334
00335 for (workers.first(); workers.current(); workers.next())
00336 workers.current()->terminate();
00337 }
00338
00339 void KResolverManager::registerThread(KResolverThread* )
00340 {
00341 }
00342
00343 void KResolverManager::unregisterThread(KResolverThread*)
00344 {
00345 runningThreads--;
00346 }
00347
00348
00349 RequestData* KResolverManager::requestData(KResolverThread *th, int maxWaitTime)
00350 {
00352
00354
00355
00356
00357 QMutexLocker locker(&mutex);
00358 RequestData *data = findData(th);
00359
00360 if (data)
00361
00362 return data;
00363
00364
00365 availableThreads++;
00366 feedWorkers.wait(&mutex, maxWaitTime);
00367 availableThreads--;
00368
00369 data = findData(th);
00370 return data;
00371 }
00372
00373 RequestData* KResolverManager::findData(KResolverThread* th)
00374 {
00376
00377
00379
00380
00381 for (RequestData *curr = newRequests.first(); curr; curr = newRequests.next())
00382 if (!curr->worker->m_finished)
00383 {
00384
00385 if (curr->obj)
00386 curr->obj->status = KResolver::InProgress;
00387 curr->worker->th = th;
00388
00389
00390 currentRequests.append(newRequests.take());
00391
00392 return curr;
00393 }
00394
00395
00396 return 0L;
00397 }
00398
00399
00400 void KResolverManager::releaseData(KResolverThread *, RequestData* data)
00401 {
00403
00405
00406
00407
00408
00409 if (data->obj)
00410 {
00411 data->obj->status = KResolver::PostProcessing;
00412 }
00413
00414 data->worker->m_finished = true;
00415 data->worker->th = 0L;
00416
00417
00418 handleFinished();
00419 }
00420
00421
00422 void KResolverManager::handleFinished()
00423 {
00424 bool redo = false;
00425 QPtrQueue<RequestData> doneRequests;
00426
00427 mutex.lock();
00428
00429
00430
00431
00432 RequestData *curr = currentRequests.last();
00433 while (curr)
00434 {
00435 if (curr->worker->th == 0L)
00436 {
00437 if (handleFinishedItem(curr))
00438 {
00439 doneRequests.enqueue(currentRequests.take());
00440 if (curr->requestor &&
00441 curr->requestor->nRequests == 0 &&
00442 curr->requestor->worker->m_finished)
00443
00444 redo = true;
00445 }
00446 }
00447
00448 curr = currentRequests.prev();
00449 }
00450
00451
00452 while (RequestData *d = doneRequests.dequeue())
00453 doNotifying(d);
00454
00455 mutex.unlock();
00456
00457 if (redo)
00458 {
00459
00460
00461 handleFinished();
00462 }
00463 }
00464
00465
00466 bool KResolverManager::handleFinishedItem(RequestData* curr)
00467
00468 {
00469
00470
00471
00472 if (curr->worker->m_finished && curr->nRequests == 0)
00473 {
00474
00475 if (curr->obj)
00476 curr->obj->status = KResolver::PostProcessing;
00477
00478 if (curr->requestor)
00479 --curr->requestor->nRequests;
00480
00481
00482
00483 return true;
00484 }
00485 return false;
00486 }
00487
00488
00489
00490 void KResolverManager::registerNewWorker(KResolverWorkerFactoryBase *factory)
00491 {
00492 workerFactories.append(factory);
00493 }
00494
00495 KResolverWorkerBase* KResolverManager::findWorker(KResolverPrivate* p)
00496 {
00498
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510 KResolverWorkerBase *worker;
00511 for (KResolverWorkerFactoryBase *factory = workerFactories.first(); factory;
00512 factory = workerFactories.next())
00513 {
00514 worker = factory->create();
00515
00516
00517 worker->input = &p->input;
00518
00519 if (worker->preprocess())
00520 {
00521
00522 if (worker->m_finished)
00523 p->status = KResolver::PostProcessing;
00524 else
00525 p->status = KResolver::Queued;
00526 return worker;
00527 }
00528
00529
00530 delete worker;
00531 }
00532
00533
00534 return 0L;
00535 }
00536
00537 void KResolverManager::doNotifying(RequestData *p)
00538 {
00540
00541
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565 if (p->obj)
00566 {
00567
00568 p->obj->mutex.lock();
00569 KResolver* parent = p->obj->parent;
00570 KResolverResults& r = p->obj->results;
00571
00572 if (p->obj->status == KResolver::Canceled)
00573 {
00574 p->obj->status = KResolver::Canceled;
00575 p->obj->errorcode = KResolver::Canceled;
00576 p->obj->syserror = 0;
00577 r.setError(KResolver::Canceled, 0);
00578 }
00579 else if (p->worker)
00580 {
00581
00582 p->worker->postprocess();
00583
00584
00585
00586 r = p->worker->results;
00587
00588
00589 r.setAddress(p->input->node, p->input->service);
00590
00591
00592
00593
00594 p->obj->errorcode = r.error();
00595 p->obj->syserror = r.systemError();
00596 p->obj->status = !r.isEmpty() ?
00597 KResolver::Success : KResolver::Failed;
00598 }
00599 else
00600 {
00601 r.empty();
00602 r.setError(p->obj->errorcode, p->obj->syserror);
00603 }
00604
00605
00606 if (!p->obj->waiting && parent)
00607
00608
00609
00610 QApplication::postEvent(parent, new QEvent((QEvent::Type)(ResolutionCompleted)));
00611
00612
00613 p->obj->mutex.unlock();
00614 }
00615 else
00616 {
00617
00618 if (p->worker)
00619 p->worker->postprocess();
00620 }
00621
00622 delete p->worker;
00623
00624
00625
00626
00627 delete p;
00628
00629
00630 notifyWaiters.wakeAll();
00631 }
00632
00633
00634
00635
00636 void KResolverManager::enqueue(KResolver *obj, RequestData *requestor)
00637 {
00638 RequestData *newrequest = new RequestData;
00639 newrequest->nRequests = 0;
00640 newrequest->obj = obj->d;
00641 newrequest->input = &obj->d->input;
00642 newrequest->requestor = requestor;
00643
00644
00645
00646 if ((newrequest->worker = findWorker(obj->d)) == 0L)
00647 {
00648
00649
00650 obj->d->status = KResolver::Failed;
00651 obj->d->errorcode = KResolver::UnsupportedFamily;
00652 obj->d->syserror = 0;
00653
00654 doNotifying(newrequest);
00655 return;
00656 }
00657
00658
00659
00660 if (requestor)
00661 requestor->nRequests++;
00662
00663 if (!newrequest->worker->m_finished)
00664 dispatch(newrequest);
00665 else if (newrequest->nRequests > 0)
00666 {
00667 mutex.lock();
00668 currentRequests.append(newrequest);
00669 mutex.unlock();
00670 }
00671 else
00672
00673 doNotifying(newrequest);
00674 }
00675
00676
00677
00678 void KResolverManager::dispatch(RequestData *data)
00679 {
00680
00681
00682
00683
00684 QMutexLocker locker(&mutex);
00685
00686
00687 newRequests.append(data);
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 if (availableThreads == 0 && runningThreads < maxThreads)
00716 {
00717
00718
00719
00720 KResolverThread *th = workers.first();
00721 while (th && th->running())
00722 th = workers.next();
00723
00724 if (th == 0L)
00725
00726 th = new KResolverThread;
00727 else
00728 workers.take();
00729
00730 th->start();
00731 workers.append(th);
00732 runningThreads++;
00733 }
00734
00735 feedWorkers.wakeAll();
00736
00737
00738 workers.first();
00739 while (workers.current())
00740 {
00741 if (!workers.current()->running())
00742 workers.remove();
00743 else
00744 workers.next();
00745 }
00746 }
00747
00748
00749 bool KResolverManager::dequeueNew(KResolver* obj)
00750 {
00751
00752
00753
00754
00755 KResolverPrivate *d = obj->d;
00756
00757
00758 RequestData *curr = newRequests.first();
00759 while (curr)
00760 if (curr->obj == d)
00761 {
00762
00763
00764 d->status = KResolver::Canceled;
00765 d->errorcode = KResolver::Canceled;
00766 d->syserror = 0;
00767 newRequests.take();
00768
00769 delete curr->worker;
00770 delete curr;
00771
00772 return true;
00773 }
00774 else
00775 curr = newRequests.next();
00776
00777
00778 curr = currentRequests.first();
00779 while (curr)
00780 if (curr->obj == d)
00781 {
00782
00783
00784 d->mutex.lock();
00785
00786 d->status = KResolver::Canceled;
00787 d->errorcode = KResolver::Canceled;
00788 d->syserror = 0;
00789
00790
00791 curr->obj = 0L;
00792 curr->input = 0L;
00793 if (curr->worker)
00794 curr->worker->input = 0L;
00795
00796 d->mutex.unlock();
00797 }
00798 else
00799 curr = currentRequests.next();
00800
00801 return false;
00802 }
00803
00804
00805
00806 void KResolverManager::dequeue(KResolver *obj)
00807 {
00808 QMutexLocker locker(&mutex);
00809 dequeueNew(obj);
00810 }
This file is part of the documentation for kdecore Library Version 3.4.1.