Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/network/kernel/qhostinfo.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the QtNetwork module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    4343#include "qhostinfo_p.h"
    4444
     45#include "QtCore/qscopedpointer.h"
    4546#include <qabstracteventdispatcher.h>
    4647#include <private/qunicodetables_p.h>
     
    6061QT_BEGIN_NAMESPACE
    6162
    62 Q_GLOBAL_STATIC(QHostInfoAgent, theAgent)
    63 void QHostInfoAgent::staticCleanup()
    64 {
    65     theAgent()->cleanup();
    66 }
     63#ifndef QT_NO_THREAD
     64Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager)
     65#endif
    6766
    6867//#define QHOSTINFO_DEBUG
     
    7473    \reentrant
    7574    \inmodule QtNetwork
    76     \ingroup io
     75    \ingroup network
    7776
    7877    QHostInfo uses the lookup mechanisms provided by the operating
     
    142141
    143142    \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 4
     143
     144    \note There is no guarantee on the order the signals will be emitted
     145    if you start multiple requests with lookupHost().
    144146
    145147    \sa abortHostLookup(), addresses(), error(), fromName()
     
    159161    qRegisterMetaType<QHostInfo>("QHostInfo");
    160162
    161 #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
    162     QWindowsSockInit bust; // makes sure WSAStartup was callled
     163    int id = theIdCounter.fetchAndAddRelaxed(1); // generate unique ID
     164
     165    if (name.isEmpty()) {
     166        QHostInfo hostInfo(id);
     167        hostInfo.setError(QHostInfo::HostNotFound);
     168        hostInfo.setErrorString(QObject::tr("No host name given"));
     169        QScopedPointer<QHostInfoResult> result(new QHostInfoResult);
     170        QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)),
     171                         receiver, member, Qt::QueuedConnection);
     172        result.data()->emitResultsReady(hostInfo);
     173        return id;
     174    }
     175
     176#ifdef QT_NO_THREAD
     177    QHostInfo hostInfo = QHostInfoAgent::fromName(name);
     178    hostInfo.setLookupId(id);
     179    QScopedPointer<QHostInfoResult> result(new QHostInfoResult);
     180    QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)),
     181                     receiver, member, Qt::QueuedConnection);
     182    result.data()->emitResultsReady(hostInfo);
     183#else
     184    QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id);
     185    QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
     186    theHostInfoLookupManager()->scheduleLookup(runnable);
    163187#endif
    164188
    165     // Support for IDNA
    166     QString lookup = QString::fromLatin1(QUrl::toAce(name));
    167 
    168     QHostInfoResult *result = new QHostInfoResult;
    169     result->autoDelete = false;
    170     QObject::connect(result, SIGNAL(resultsReady(QHostInfo)),
    171                      receiver, member);
    172     int id = result->lookupId = theIdCounter.fetchAndAddRelaxed(1);
    173 
    174     if (lookup.isEmpty()) {
    175         QHostInfo info(id);
    176         info.setError(QHostInfo::HostNotFound);
    177         info.setErrorString(QObject::tr("No host name given"));
    178         QMetaObject::invokeMethod(result, "emitResultsReady", Qt::QueuedConnection,
    179                                   Q_ARG(QHostInfo, info));
    180         result->autoDelete = true;
    181         return id;
    182     }
    183 
    184     QHostInfoAgent *agent = theAgent();
    185     agent->addHostName(lookup, result);
    186 
    187 #if !defined QT_NO_THREAD
    188     if (!agent->isRunning())
    189         agent->start();
     189    return id;
     190}
     191
     192/*!
     193    Aborts the host lookup with the ID \a id, as returned by lookupHost().
     194
     195    \sa lookupHost(), lookupId()
     196*/
     197void QHostInfo::abortHostLookup(int id)
     198{
     199#ifndef QT_NO_THREAD
     200    theHostInfoLookupManager()->abortLookup(id);
    190201#else
    191 //    if (!agent->isRunning())
    192         agent->run();
    193 //    else
    194 //      agent->wakeOne();
     202    // we cannot abort if it was non threaded.. the result signal has already been posted
     203    Q_UNUSED(id);
    195204#endif
    196     return id;
    197 }
    198 
    199 /*!
    200     Aborts the host lookup with the ID \a id, as returned by lookupHost().
    201 
    202     \sa lookupHost(), lookupId()
    203 */
    204 void QHostInfo::abortHostLookup(int id)
    205 {
    206     QHostInfoAgent *agent = theAgent();
    207     agent->abortLookup(id);
    208205}
    209206
     
    227224#endif
    228225
    229     if (!name.isEmpty())
    230         return QHostInfoAgent::fromName(QLatin1String(QUrl::toAce(name)));
    231 
    232     QHostInfo retval;
    233     retval.d->err = HostNotFound;
    234     retval.d->errorStr = QObject::tr("No host name given");
    235     return retval;
    236 }
    237 
    238 /*!
    239     \internal
    240     Pops a query off the queries list, performs a blocking call to
    241     QHostInfoAgent::lookupHost(), and emits the resultsReady()
    242     signal. This process repeats until the queries list is empty.
    243 */
    244 void QHostInfoAgent::run()
    245 {
    246 #ifndef QT_NO_THREAD
    247     // Dont' allow thread termination during event delivery, but allow it
    248     // during the actual blocking host lookup stage.
    249     setTerminationEnabled(false);
    250     forever
    251 #endif
    252     {
    253         QHostInfoQuery *query;
    254         {
    255 #ifndef QT_NO_THREAD
    256             // the queries list is shared between threads. lock all
    257             // access to it.
    258             QMutexLocker locker(&mutex);
    259             if (!quit && queries.isEmpty())
    260                 cond.wait(&mutex);
    261             if (quit) {
    262                 // Reset the quit variable in case QCoreApplication is
    263                 // destroyed and recreated.
    264                 quit = false;
    265                 break;
    266             }
    267             if (queries.isEmpty())
    268                 continue;
    269 #else
    270             if (queries.isEmpty())
    271                 return;
    272 #endif
    273             query = queries.takeFirst();
    274             pendingQueryId = query->object->lookupId;
    275         }
    276 
    277 #if defined(QHOSTINFO_DEBUG)
    278         qDebug("QHostInfoAgent::run(%p): looking up \"%s\"", this,
    279                query->hostName.toLatin1().constData());
    280 #endif
    281 
    282 #ifndef QT_NO_THREAD
    283         // Start query - allow termination at this point, but not outside. We
    284         // don't want to all termination during event delivery, but we don't
    285         // want the lookup to prevent the app from quitting (the agent
    286         // destructor terminates the thread).
    287         setTerminationEnabled(true);
    288 #endif
    289         QHostInfo info = fromName(query->hostName);
    290 #ifndef QT_NO_THREAD
    291         setTerminationEnabled(false);
    292 #endif
    293 
    294         int id = query->object->lookupId;
    295         info.setLookupId(id);
    296         if (pendingQueryId == id)
    297             query->object->emitResultsReady(info);
    298         delete query;
    299     }
     226    return QHostInfoAgent::fromName(name);
    300227}
    301228
     
    328255*/
    329256QHostInfo::QHostInfo(const QHostInfo &other)
    330     : d(new QHostInfoPrivate(*other.d))
     257    : d(new QHostInfoPrivate(*other.d.data()))
    331258{
    332259}
     
    338265QHostInfo &QHostInfo::operator=(const QHostInfo &other)
    339266{
    340     *d = *other.d;
     267    *d.data() = *other.d.data();
    341268    return *this;
    342269}
     
    347274QHostInfo::~QHostInfo()
    348275{
    349     delete d;
    350276}
    351277
     
    477403*/
    478404
     405#ifndef QT_NO_THREAD
     406QHostInfoRunnable::QHostInfoRunnable(QString hn, int i) : toBeLookedUp(hn), id(i)
     407{
     408    setAutoDelete(true);
     409}
     410
     411// the QHostInfoLookupManager will at some point call this via a QThreadPool
     412void QHostInfoRunnable::run()
     413{
     414    QHostInfoLookupManager *manager = theHostInfoLookupManager();
     415    // check aborted
     416    if (manager->wasAborted(id)) {
     417        manager->lookupFinished(this);
     418        return;
     419    }
     420
     421    // check cache
     422    // FIXME
     423
     424    // if not in cache: OS lookup
     425    QHostInfo hostInfo = QHostInfoAgent::fromName(toBeLookedUp);
     426
     427    // save to cache
     428    // FIXME
     429
     430    // check aborted again
     431    if (manager->wasAborted(id)) {
     432        manager->lookupFinished(this);
     433        return;
     434    }
     435
     436    // signal emission
     437    hostInfo.setLookupId(id);
     438    resultEmitter.emitResultsReady(hostInfo);
     439
     440    manager->lookupFinished(this);
     441
     442    // thread goes back to QThreadPool
     443}
     444
     445QHostInfoLookupManager::QHostInfoLookupManager() : mutex(QMutex::Recursive), wasDeleted(false)
     446{
     447    moveToThread(QCoreApplicationPrivate::mainThread());
     448    threadPool.setMaxThreadCount(5); // do 5 DNS lookups in parallel
     449}
     450
     451QHostInfoLookupManager::~QHostInfoLookupManager()
     452{
     453    wasDeleted = true;
     454}
     455
     456void QHostInfoLookupManager::work()
     457{
     458    if (wasDeleted)
     459        return;
     460
     461    // goals of this function:
     462    //  - launch new lookups via the thread pool
     463    //  - make sure only one lookup per host/IP is in progress
     464
     465    QMutexLocker locker(&mutex);
     466
     467    if (!finishedLookups.isEmpty()) {
     468        // remove ID from aborted if it is in there
     469        for (int i = 0; i < finishedLookups.length(); i++) {
     470           abortedLookups.removeAll(finishedLookups.at(i)->id);
     471        }
     472
     473        finishedLookups.clear();
     474    }
     475
     476    if (!postponedLookups.isEmpty()) {
     477        // try to start the postponed ones
     478
     479        QMutableListIterator<QHostInfoRunnable*> iterator(postponedLookups);
     480        while (iterator.hasNext()) {
     481            QHostInfoRunnable* postponed = iterator.next();
     482
     483            // check if none of the postponed hostnames is currently running
     484            bool alreadyRunning = false;
     485            for (int i = 0; i < currentLookups.length(); i++) {
     486                if (currentLookups.at(i)->toBeLookedUp == postponed->toBeLookedUp) {
     487                    alreadyRunning = true;
     488                    break;
     489                }
     490            }
     491            if (!alreadyRunning) {
     492                iterator.remove();
     493                scheduledLookups.prepend(postponed); // prepend! we want to finish it ASAP
     494            }
     495        }
     496    }
     497
     498    if (!scheduledLookups.isEmpty()) {
     499        // try to start the new ones
     500        QMutableListIterator<QHostInfoRunnable*> iterator(scheduledLookups);
     501        while (iterator.hasNext()) {
     502            QHostInfoRunnable *scheduled = iterator.next();
     503
     504            // check if a lookup for this host is already running, then postpone
     505            for (int i = 0; i < currentLookups.size(); i++) {
     506                if (currentLookups.at(i)->toBeLookedUp == scheduled->toBeLookedUp) {
     507                    iterator.remove();
     508                    postponedLookups.append(scheduled);
     509                    scheduled = 0;
     510                    break;
     511                }
     512            }
     513
     514            if (scheduled && threadPool.tryStart(scheduled)) {
     515                // runnable now running in new thread, track this in currentLookups
     516                iterator.remove();
     517                currentLookups.append(scheduled);
     518            } else if (scheduled) {
     519                // wanted to start, but could not because thread pool is busy
     520                break;
     521            } else {
     522                // was postponed, continue iterating
     523                continue;
     524            }
     525        };
     526    }
     527}
     528
     529// called by QHostInfo
     530void QHostInfoLookupManager::scheduleLookup(QHostInfoRunnable *r)
     531{
     532    if (wasDeleted)
     533        return;
     534
     535    QMutexLocker locker(&this->mutex);
     536    scheduledLookups.enqueue(r);
     537    work();
     538}
     539
     540// called by QHostInfo
     541void QHostInfoLookupManager::abortLookup(int id)
     542{
     543    if (wasDeleted)
     544        return;
     545
     546    QMutexLocker locker(&this->mutex);
     547    if (!abortedLookups.contains(id))
     548        abortedLookups.append(id);
     549}
     550
     551// called from QHostInfoRunnable
     552bool QHostInfoLookupManager::wasAborted(int id)
     553{
     554    if (wasDeleted)
     555        return true;
     556
     557    QMutexLocker locker(&this->mutex);
     558    return abortedLookups.contains(id);
     559}
     560
     561// called from QHostInfoRunnable
     562void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r)
     563{
     564    if (wasDeleted)
     565        return;
     566
     567    QMutexLocker locker(&this->mutex);
     568    currentLookups.removeOne(r);
     569    finishedLookups.append(r);
     570    work();
     571}
     572
     573#endif // QT_NO_THREAD
     574
    479575QT_END_NAMESPACE
Note: See TracChangeset for help on using the changeset viewer.