59 #include "QtCore/qmutex.h" |
59 #include "QtCore/qmutex.h" |
60 #include "QtCore/qwaitcondition.h" |
60 #include "QtCore/qwaitcondition.h" |
61 #include "QtCore/qobject.h" |
61 #include "QtCore/qobject.h" |
62 #include "QtCore/qpointer.h" |
62 #include "QtCore/qpointer.h" |
63 |
63 |
64 #if !defined QT_NO_THREAD |
64 #ifndef QT_NO_THREAD |
65 #include "QtCore/qthread.h" |
65 #include "QtCore/qthread.h" |
66 # define QHostInfoAgentBase QThread |
66 #include "QtCore/qthreadpool.h" |
67 #else |
67 #include "QtCore/qmutex.h" |
68 # define QHostInfoAgentBase QObject |
68 #include "QtCore/qrunnable.h" |
|
69 #include "QtCore/qlist.h" |
|
70 #include "QtCore/qqueue.h" |
69 #endif |
71 #endif |
70 |
72 |
71 QT_BEGIN_NAMESPACE |
73 QT_BEGIN_NAMESPACE |
72 |
|
73 static const int QHOSTINFO_THREAD_WAIT = 250; // ms |
|
74 |
74 |
75 class QHostInfoResult : public QObject |
75 class QHostInfoResult : public QObject |
76 { |
76 { |
77 Q_OBJECT |
77 Q_OBJECT |
78 public Q_SLOTS: |
78 public Q_SLOTS: |
79 inline void emitResultsReady(const QHostInfo &info) |
79 inline void emitResultsReady(const QHostInfo &info) |
80 { |
80 { |
81 emit resultsReady(info); |
81 emit resultsReady(info); |
82 if (autoDelete) |
|
83 delete this; |
|
84 } |
82 } |
85 |
83 |
86 Q_SIGNALS: |
84 Q_SIGNALS: |
87 void resultsReady(const QHostInfo &info); |
85 void resultsReady(const QHostInfo info); |
88 |
|
89 public: |
|
90 int lookupId; |
|
91 bool autoDelete; |
|
92 }; |
86 }; |
93 |
87 |
94 struct QHostInfoQuery |
88 // needs to be QObject because fromName calls tr() |
95 { |
89 class QHostInfoAgent : public QObject |
96 inline QHostInfoQuery() : object(0) {} |
|
97 inline ~QHostInfoQuery() { delete object; } |
|
98 inline QHostInfoQuery(const QString &name, QHostInfoResult *result) |
|
99 : hostName(name), object(result) {} |
|
100 |
|
101 QString hostName; |
|
102 QHostInfoResult *object; |
|
103 }; |
|
104 |
|
105 class QHostInfoAgent : public QHostInfoAgentBase |
|
106 { |
90 { |
107 Q_OBJECT |
91 Q_OBJECT |
108 public: |
92 public: |
109 inline QHostInfoAgent() |
|
110 { |
|
111 // There is a chance that there will be two instances of |
|
112 // QHostInfoAgent if two threads try to get Q_GLOBAL_STATIC |
|
113 // object at the same time. The second object will be deleted |
|
114 // immediately before anyone uses it, but we need to be |
|
115 // careful about what we do in the constructor. |
|
116 static QBasicAtomicInt done = Q_BASIC_ATOMIC_INITIALIZER(0); |
|
117 if (done.testAndSetRelaxed(0, 1)) |
|
118 qAddPostRoutine(staticCleanup); |
|
119 moveToThread(QCoreApplicationPrivate::mainThread()); |
|
120 quit = false; |
|
121 pendingQueryId = -1; |
|
122 } |
|
123 inline ~QHostInfoAgent() |
|
124 { cleanup(); } |
|
125 |
|
126 void run(); |
|
127 static QHostInfo fromName(const QString &hostName); |
93 static QHostInfo fromName(const QString &hostName); |
128 |
|
129 inline void addHostName(const QString &name, QHostInfoResult *result) |
|
130 { |
|
131 QMutexLocker locker(&mutex); |
|
132 queries << new QHostInfoQuery(name, result); |
|
133 cond.wakeOne(); |
|
134 } |
|
135 |
|
136 inline void abortLookup(int id) |
|
137 { |
|
138 QMutexLocker locker(&mutex); |
|
139 for (int i = 0; i < queries.size(); ++i) { |
|
140 QHostInfoResult *result = queries.at(i)->object; |
|
141 if (result->lookupId == id) { |
|
142 result->disconnect(); |
|
143 delete queries.takeAt(i); |
|
144 return; |
|
145 } |
|
146 } |
|
147 if (pendingQueryId == id) |
|
148 pendingQueryId = -1; |
|
149 } |
|
150 |
|
151 static void staticCleanup(); |
|
152 |
|
153 public Q_SLOTS: |
|
154 inline void cleanup() |
|
155 { |
|
156 { |
|
157 QMutexLocker locker(&mutex); |
|
158 qDeleteAll(queries); |
|
159 queries.clear(); |
|
160 quit = true; |
|
161 cond.wakeOne(); |
|
162 } |
|
163 #ifndef QT_NO_THREAD |
|
164 if (!wait(QHOSTINFO_THREAD_WAIT)) |
|
165 terminate(); |
|
166 wait(); |
|
167 #endif |
|
168 } |
|
169 |
|
170 private: |
|
171 QList<QHostInfoQuery *> queries; |
|
172 QMutex mutex; |
|
173 QWaitCondition cond; |
|
174 volatile bool quit; |
|
175 int pendingQueryId; |
|
176 }; |
94 }; |
177 |
95 |
178 class QHostInfoPrivate |
96 class QHostInfoPrivate |
179 { |
97 { |
180 public: |
98 public: |
190 QList<QHostAddress> addrs; |
108 QList<QHostAddress> addrs; |
191 QString hostName; |
109 QString hostName; |
192 int lookupId; |
110 int lookupId; |
193 }; |
111 }; |
194 |
112 |
|
113 #ifndef QT_NO_THREAD |
|
114 // the following classes are used for the (normal) case: We use multiple threads to lookup DNS |
|
115 |
|
116 class QHostInfoRunnable : public QRunnable |
|
117 { |
|
118 public: |
|
119 QHostInfoRunnable (QString hn, int i); |
|
120 void run(); |
|
121 |
|
122 QString toBeLookedUp; |
|
123 int id; |
|
124 QHostInfoResult resultEmitter; |
|
125 }; |
|
126 |
|
127 class QHostInfoLookupManager : public QObject |
|
128 { |
|
129 Q_OBJECT |
|
130 public: |
|
131 QHostInfoLookupManager(); |
|
132 ~QHostInfoLookupManager(); |
|
133 |
|
134 void work(); |
|
135 |
|
136 // called from QHostInfo |
|
137 void scheduleLookup(QHostInfoRunnable *r); |
|
138 void abortLookup(int id); |
|
139 |
|
140 // called from QHostInfoRunnable |
|
141 void lookupFinished(QHostInfoRunnable *r); |
|
142 bool wasAborted(int id); |
|
143 |
|
144 protected: |
|
145 QList<QHostInfoRunnable*> currentLookups; // in progress |
|
146 QList<QHostInfoRunnable*> postponedLookups; // postponed because in progress for same host |
|
147 QQueue<QHostInfoRunnable*> scheduledLookups; // not yet started |
|
148 QList<QHostInfoRunnable*> finishedLookups; // recently finished |
|
149 QList<int> abortedLookups; // ids of aborted lookups |
|
150 |
|
151 QThreadPool threadPool; |
|
152 |
|
153 QMutex mutex; |
|
154 |
|
155 bool wasDeleted; |
|
156 }; |
|
157 #endif |
|
158 |
195 QT_END_NAMESPACE |
159 QT_END_NAMESPACE |
196 |
160 |
197 #endif // QHOSTINFO_P_H |
161 #endif // QHOSTINFO_P_H |