summaryrefslogtreecommitdiff
path: root/ACE/ace/QtReactor.h
blob: c3ccb82f7f3dce273ba5e60e860f41efb46f6243 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
// -*- C++ -*-

//=============================================================================
/**
 *  @file    QtReactor.h
 *
 *  $Id$
 *
 *  @author Hamish Friedlander <ullexco@wave.co.nz>
 *  @author Balachandran Natarajan <bala@cs.wustl.edu>
 */
//=============================================================================

#ifndef ACE_QTREACTOR_H
#define ACE_QTREACTOR_H

#include /**/ "ace/pre.h"

#include "ace/ACE_QtReactor_export.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

#include "ace/Select_Reactor.h"
#include "ace/Map_Manager.h"

// QT toolkit specific includes.
#include /**/ <qapplication.h>
#include /**/ <qobject.h>
#include /**/ <qsocketnotifier.h>
#include /**/ <qtimer.h>

ACE_BEGIN_VERSIONED_NAMESPACE_DECL

/**
 * @class ACE_QtReactor
 *
 * @brief An object-oriented event demultiplexor and event handler
 * dispatcher that uses the Qt Library. This class declaration
 * also uses the extension facilities  provided by the Qt. So,
 * readers  of the class declaration should not be upset with
 * the appearence of the Keywords like Q_OBJECT, private slots
 * etc. They are specific to Qt which uses these as a call back
 * methods implementation mechanism.
 *
 * \note Marek Brudka <mbrudka@elka.pw.edu.pl>: ACE_QtReactor was
 * quickly bugfixed to meet ACE 5.4.2 (6.0.0?) deadline.
 * While it passes QtReactor_Test now, there is a great
 * room for improvements as the implementation is rather inefficient
 * and obfuscated
 * To be more specific:
 * - reset_timeout always creates and removes qtimer after each
 * timeout event! Obviously, for fast triggering timers this may
 * lead to excessive memory management.
 * - create/destroy_notifiers_for_handle may also be reworked to
 * establish more clean relations between handles and QSocketNotifiers.
 * - read/write_exception_event disable now SocketNotifier for a while
 * to clear pending events. The cost of this operation is high: two hash
 * acces in ACE and at least two next ones in Qt. This makes QtReator slow,
 * but how clear pending events another way ?
 * - there is qapplication() mutator, which sets new qapplication for
 * QtReactor. This mutator violates implicit assumption about the
 * relations between QTimer and QSocketNotifiers and QApplication for
 * this reactor, namely one may expect that after qapplication(), none
 * of QtReactor artifacts is bound to old qapplication. That's not true
 * now, as QTimer and QSocketNotifiers are not reparent to new
 * QApplication. As a result, the sequence:
 * QApplication *old_qapp = new QApplication(..);
 * QtReactor qreactor( old_qapp);
 * // .. register handlers, schedule_timers etc
 * QApplication *new_qapp = new QApplication(..);
 * qreactor.qpplication( new_qapp );
 * delete old_qapp;
 * almost always leads to problems and memory violation, because
 * QSocketNotifiers are released by old_qapp. Therefore QtReactor
 * should not be reparent now by setting new qapplication.
 * - the lifecycle of Qt objects in ACE contects is rather mysterious
 * and should be made more explicit.
 * - valgrind reports a small memory leak in QtReactor_Test, though as for now
 * it is not clear if the leak is introduced by  QtReactor, or rather incorrect
 * memory management in QtReactor_Test.
 */
class ACE_QtReactor_Export ACE_QtReactor
  : public QObject,
    public ACE_Select_Reactor
{

    Q_OBJECT

public:
    /** \brief Constructor follows  @ACE_Select_Reactor
        \param QApplication *qapp, qapplication which runs events loop
    */
    ACE_QtReactor (QApplication *qapp = 0,
        ACE_Sig_Handler * = 0,
        ACE_Timer_Queue * = 0,
        int disable_notify_pipe = 0,
        ACE_Reactor_Notify *notify = 0,
        int mask_signals = 1,
        int s_queue = ACE_SELECT_TOKEN::FIFO);

    /** \brief Constructor follows @ACE_Select_Reactor
        \param QApplication *qapp, qapplication which runs events loop
    */
    ACE_QtReactor (size_t size,
        QApplication *qapp = 0,
        int restart = 0,
        ACE_Sig_Handler * = 0,
        ACE_Timer_Queue * = 0,
        int disable_notify_pipe = 0,
        ACE_Reactor_Notify *notify = 0,
        int mask_signals = 1,
        int s_queue = ACE_SELECT_TOKEN::FIFO);

    virtual ~ACE_QtReactor (void);

    void qapplication (QApplication *qapp);

    // = Timer operations.
    virtual long schedule_timer (ACE_Event_Handler *handler,
        const void *arg,
        const ACE_Time_Value &delay_time,
        const ACE_Time_Value &interval);

    virtual int  cancel_timer (ACE_Event_Handler *handler,
        int dont_call_handle_close = 1);

    virtual int  cancel_timer (long timer_id,
        const void **arg = 0,
        int dont_call_handle_close = 1);

protected:

    // = Register timers/handles with Qt

    /// Register a single <handler>.
    virtual int register_handler_i (ACE_HANDLE handle,
        ACE_Event_Handler *handler,
        ACE_Reactor_Mask mask);

    /// Register a set of <handlers> with Qt.
    virtual int register_handler_i (const ACE_Handle_Set &handles,
        ACE_Event_Handler *handler,
        ACE_Reactor_Mask mask);


    /// Remove the <handler> associated with this <handle>.
    virtual int remove_handler_i (ACE_HANDLE handle,
        ACE_Reactor_Mask mask);

    /// Remove a set of <handles>.
    virtual int remove_handler_i (const ACE_Handle_Set &handles,
        ACE_Reactor_Mask mask);

    /// Wait for events to occur.
    virtual int wait_for_multiple_events (ACE_Select_Reactor_Handle_Set &handle_set,
        ACE_Time_Value *max_wait_time);

    virtual int QtWaitForMultipleEvents (int width,
        ACE_Select_Reactor_Handle_Set &wait_set,
        ACE_Time_Value *max_wait_time);

    virtual int bit_ops (ACE_HANDLE handle,
        ACE_Reactor_Mask mask,
        ACE_Select_Reactor_Handle_Set &handle_set,
        int ops);

    int set_enable_flag_by_mask (int flag_value, ACE_HANDLE handle, ACE_Reactor_Mask mask);
    void create_notifiers_for_handle (ACE_HANDLE handle);
    void destroy_notifiers_for_handle (ACE_HANDLE handle);

    // Wait for Qt events to occur

    /// Some Qt stuff that we need to have
    QApplication *qapp_ ;

    /// Typedef of a map.
    typedef ACE_Map_Manager<ACE_HANDLE, QSocketNotifier *, ACE_Null_Mutex> MAP;

    /// A notifier for a read
    MAP read_notifier_;

    /// A write notifier
    MAP write_notifier_;

    /// An exception notifier
    MAP exception_notifier_;

    /// The timer class that would provide timer-sgnals & single-shot timers
    QTimer *qtime_ ;

private:
    /// This method ensures there's an Qt timeout for the first timeout
    /// in the Reactor's Timer_Queue.
    void reset_timeout (void);
    /// reopens notification pipe to create SocketNotifier for it
    void reopen_notification_pipe(void);
    /// Deny access since member-wise won't work...
    ACE_QtReactor (const ACE_QtReactor &);
    ACE_QtReactor &operator= (const ACE_QtReactor &);

private slots:

    // These are all part of the communication mechanism adopted in Qt.
    /// Dispatch a Read Event
    void read_event (int FD);

    /// Dispatch a Write Event
    void write_event (int FD);

    /// Dispatch an exception event
    void exception_event (int FD);

    /// Dispach a timeout event
    void timeout_event (void);
};

ACE_END_VERSIONED_NAMESPACE_DECL

#include /**/ "ace/post.h"
#endif /* ACE_QTREACTOR_H */