1
/****************************************************************************
2
**
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
**
7
** This file is part of the QtCore module of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
33
**
34
**
35
**
36
**
37
**
38
** $QT_END_LICENSE$
39
**
40
****************************************************************************/
41
42
#ifndef QEVENTDISPATCHER_SYMBIAN_P_H
43
#define QEVENTDISPATCHER_SYMBIAN_P_H
44
45
//
46
//  W A R N I N G
47
//  -------------
48
//
49
// This file is not part of the Qt API.  It exists purely as an
50
// implementation detail.  This header file may change from version to
51
// version without notice, or even be removed.
52
//
53
// We mean it.
54
//
55
56
#include <qhash.h>
57
#include <qset.h>
58
#include <qshareddata.h>
59
#include <qabstracteventdispatcher.h>
60
#include <private/qabstracteventdispatcher_p.h>
61
#include <qthread.h>
62
#include <qmutex.h>
63
#include <qwaitcondition.h>
64
#include <qsocketnotifier.h>
65
#include <qdatetime.h>
66
#include <qelapsedtimer.h>
67
68
#include <e32base.h>
69
70
#include <sys/types.h>
71
#include <sys/socket.h>
72
#include <sys/select.h>
73
74
QT_BEGIN_NAMESPACE
75
76
77
class QEventDispatcherSymbian;
78
class QTimerActiveObject;
79
80
class Q_CORE_EXPORT QActiveObject : public CActive
81
{
82
public:
83
    QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher);
84
    ~QActiveObject();
85
86
    bool maybeDeferSocketEvent();
87
    bool maybeQueueForLater();
88
    void reactivateAndComplete();
89
protected:
90
    QEventDispatcherSymbian *m_dispatcher;
91
    QThreadData *m_threadData;
92
93
private:
94
    bool m_hasAlreadyRun : 1;
95
    bool m_hasRunAgain : 1;
96
    int m_iterationCount;
97
};
98
99
class QWakeUpActiveObject : public CActive
100
{
101
public:
102
    QWakeUpActiveObject(QEventDispatcherSymbian *dispatcher);
103
    ~QWakeUpActiveObject();
104
105
    void Complete();
106
107
protected:
108
    void DoCancel();
109
    void RunL();
110
111
private:
112
    QEventDispatcherSymbian *m_dispatcher;
113
    TThreadId m_hostThreadId;
114
};
115
116
struct SymbianTimerInfo : public QSharedData
117
{
118
    SymbianTimerInfo();
119
    ~SymbianTimerInfo();
120
121
    int timerId;
122
    int interval;
123
    int msLeft;
124
    bool inTimerEvent;
125
    QObject *receiver;
126
    QTimerActiveObject *timerAO;
127
    QEventDispatcherSymbian *dispatcher;
128
};
129
130
typedef QExplicitlySharedDataPointer<SymbianTimerInfo> SymbianTimerInfoPtr;
131
132
// This is a bit of a proxy class. See comments in SetActive and Start for details.
133
class QTimerActiveObject : public QActiveObject
134
{
135
public:
136
    QTimerActiveObject(QEventDispatcherSymbian *dispatcher, SymbianTimerInfo *timerInfo);
137
    ~QTimerActiveObject();
138
139
    void Start();
140
141
protected:
142
    void DoCancel();
143
    void RunL();
144
145
private:
146
    void Run();
147
    void StartTimer();
148
149
private:
150
    SymbianTimerInfo *m_timerInfo;
151
    QElapsedTimer m_timeoutTimer;
152
    int m_expectedTimeSinceLastEvent;
153
    RTimer m_rTimer;
154
};
155
156
class QCompleteDeferredAOs : public CActive
157
{
158
public:
159
    QCompleteDeferredAOs(QEventDispatcherSymbian *dispatcher);
160
    ~QCompleteDeferredAOs();
161
162
    void complete();
163
164
protected:
165
    void DoCancel();
166
    void RunL();
167
168
private:
169
    QEventDispatcherSymbian *m_dispatcher;
170
};
171
172
class QSocketActiveObject : public QActiveObject
173
{
174
public:
175
    QSocketActiveObject(QEventDispatcherSymbian *dispatcher, QSocketNotifier *notifier);
176
    ~QSocketActiveObject();
177
178
    void deleteLater();
179
180
protected:
181
    void DoCancel();
182
    void RunL();
183
    void run();
184
185
private:
186
    QSocketNotifier *m_notifier;
187
    bool m_inSocketEvent;
188
    bool m_deleteLater;
189
190
    friend class QEventDispatcherSymbian;
191
};
192
193
class QSelectThread : public QThread
194
{
195
    Q_DECLARE_PRIVATE(QThread)
196
197
public:
198
    QSelectThread();
199
    ~QSelectThread();
200
201
    void requestSocketEvents ( QSocketNotifier *notifier, TRequestStatus *status );
202
    void cancelSocketEvents ( QSocketNotifier *notifier );
203
    void restart();
204
    void stop();
205
206
protected:
207
    void run();
208
209
private:
210
    int updateSocketSet(QSocketNotifier::Type type, fd_set *fds);
211
    void updateActivatedNotifiers(QSocketNotifier::Type type, fd_set *fds);
212
213
private:
214
    int m_pipeEnds[2];
215
    QHash<QSocketNotifier *, TRequestStatus *> m_AOStatuses;
216
    QMutex m_mutex;
217
    QWaitCondition m_waitCond;
218
    bool m_quit;
219
};
220
221
class Q_CORE_EXPORT CQtActiveScheduler : public CActiveScheduler
222
{
223
public: // from CActiveScheduler
224
    virtual void Error(TInt aError) const;
225
};
226
227
class Q_CORE_EXPORT QEventDispatcherSymbian : public QAbstractEventDispatcher
228
{
229
    Q_OBJECT
230
    Q_DECLARE_PRIVATE(QAbstractEventDispatcher)
231
232
public:
233
    QEventDispatcherSymbian(QObject *parent = 0);
234
    ~QEventDispatcherSymbian();
235
236
    void flush();
237
    bool hasPendingEvents();
238
    void interrupt();
239
    bool processEvents ( QEventLoop::ProcessEventsFlags flags );
240
    void registerSocketNotifier ( QSocketNotifier * notifier );
241
    void registerTimer ( int timerId, int interval, QObject * object );
242
    QList<TimerInfo> registeredTimers ( QObject * object ) const;
243
    void unregisterSocketNotifier ( QSocketNotifier * notifier );
244
    bool unregisterTimer ( int timerId );
245
    bool unregisterTimers ( QObject * object );
246
    void wakeUp();
247
248
    void startingUp();
249
    void closingDown();
250
251
    void timerFired(int timerId, QTimerActiveObject *ao);
252
    void wakeUpWasCalled(QWakeUpActiveObject *ao);
253
    void reactivateSocketNotifier(QSocketNotifier *notifier);
254
255
    void addDeferredActiveObject(QActiveObject *object);
256
    void removeDeferredActiveObject(QActiveObject *object);
257
    void queueDeferredActiveObjectsCompletion();
258
    // Can be overridden to activate local active objects too, but do call baseclass!
259
    virtual void reactivateDeferredActiveObjects();
260
    inline int iterationCount() const { return m_iterationCount; }
261
262
    void addDeferredSocketActiveObject(QActiveObject *object);
263
    inline bool areSocketEventsBlocked() const { return m_noSocketEvents; }
264
265
    static void RequestComplete(TRequestStatus *&status, TInt reason);
266
    static void RequestComplete(RThread &threadHandle, TRequestStatus *&status, TInt reason);
267
268
    void activeObjectError(int error);
269
270
private:
271
    bool sendPostedEvents();
272
    bool sendDeferredSocketEvents();
273
274
    QSelectThread& selectThread();
275
private:
276
    QSelectThread *m_selectThread;
277
278
    CQtActiveScheduler *m_activeScheduler;
279
280
    QHash<int, SymbianTimerInfoPtr> m_timerList;
281
    QHash<QSocketNotifier *, QSocketActiveObject *> m_notifiers;
282
283
    QWakeUpActiveObject *m_wakeUpAO;
284
    QCompleteDeferredAOs *m_completeDeferredAOs;
285
286
    volatile bool m_interrupt;
287
    QAtomicInt m_wakeUpDone;
288
289
    unsigned char m_iterationCount;
290
    bool m_insideTimerEvent;
291
    bool m_noSocketEvents;
292
    //deferred until socket events are enabled
293
    QList<QActiveObject *> m_deferredSocketEvents;
294
295
    QList<QActiveObject *> m_deferredActiveObjects;
296
297
    int m_delay;
298
    int m_avgEventTime;
299
    QElapsedTimer m_lastIdleRequestTimer;
300
    int m_oomErrorCount;
301
    QElapsedTimer m_oomErrorTimer;
302
};
303
304
#ifdef QT_DEBUG
305
# define VERIFY_PENDING_REQUEST_STATUS \
306
    Q_ASSERT(status->Int() == KRequestPending);
307
#else
308
# define VERIFY_PENDING_REQUEST_STATUS
309
#endif
310
311
// Convenience functions for doing some sanity checking on our own complete code.
312
// Unless QT_DEBUG is defined, it is exactly equivalent to the Symbian version.
313
inline void QEventDispatcherSymbian::RequestComplete(TRequestStatus *&status, TInt reason)
314
{
315
    VERIFY_PENDING_REQUEST_STATUS
316
    User::RequestComplete(status, reason);
317
}
318
inline void QEventDispatcherSymbian::RequestComplete(RThread &threadHandle, TRequestStatus *&status, TInt reason)
319
{
320
    VERIFY_PENDING_REQUEST_STATUS
321
    threadHandle.RequestComplete(status, reason);
322
}
323
324
#undef VERIFY_PENDING_REQUEST_STATUS
325
326
QT_END_NAMESPACE
327
328
#endif // QEVENTDISPATCHER_SYMBIAN_P_H