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