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 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
|
// $Id: test_signals_2.cpp 91671 2010-09-08 18:39:23Z johnnyw $
// Test the ability of the Reactor/Signal_Handler to register multiple
// handler per-signal.
/* This test works as follows:
1. To test the "original" semantics of ACE (i.e., only one
ACE_Event_Handler can be registered per signal), you don't
need to do anything special. Existing programs work the
same since giving the Reactor's constructor a 0 value
(which is the default argument, BTW) instructs it to behave
as before. When a 0 is given, the ACE_Reactor's
constructor/open method creates an instance of
ACE_Sig_Handler and assigns this to an internal pointer.
This pointer is then used to dispatch all signal-related
methods within the Reactor. The default ACE_Sig_Handler
only allows *one* ACE_Event_Handler to be registered
per-signal.
To run this version of the test do the following:
% ./test-signal
./test_signals
waiting for SIGINT or SIGQUIT
^C
signal Interrupt occurred in Sig_Handler_2 (fruity, 0, 0) with count = 1
waiting for SIGINT or SIGQUIT
^\
signal Quit occurred in Sig_Handler_2 (fruity, 0, 0) with count = 2
shutting down SIGQUIT in Sig_Handler_2 (fruity, 0, 0)
waiting for SIGINT or SIGQUIT
^C
signal Interrupt occurred in Sig_Handler_2 (fruity, 0, 0) with count = 3
waiting for SIGINT or SIGQUIT
^\Quit (core dumped)
Note that in this test only one handler (the last one --
"Sig_Handler_2 (fruity)") is actually registered. BTW, the
core dump is the expected behavior since the default
disposition is restored when there are no more handlers
(see the code below).
2. To test the "multiple handlers per-signal semantics", you
need to pass the constructor/open method of the ACE_Reactor
a pointer to a an instance of ACE_Sig_Handlers (note the
plural "s"). ACE_Sig_Handlers is a class that derives from
ACE_Sig_Handler. The difference between these two classes
is that (1) ACE_Sig_Handlers::register_signal allows
multiple ACE_Event_Handlers to be registered per-signal and
(2) it enables SA_RESTART by default. This class also
implements Detlef Becker's algorithm for integrating ACE
signal handling with 3rd party libraries.
To run this version of the test do the following:
% ./test_signals 1
waiting for SIGINT or SIGQUIT
^C
signal Interrupt occurred in external handler!
signal Interrupt occurred in Sig_Handler_1 (howdy, 3, 1) with count = 1
shutting down SIGINT in Sig_Handler_1 (howdy, 3, 1)
signal Interrupt occurred in Sig_Handler_1 (doody, 5, 4) with count = 1
shutting down SIGINT in Sig_Handler_1 (doody, 5, 4)
signal Interrupt occurred in Sig_Handler_2 (tutty, 7, 6) with count = 1
signal Interrupt occurred in Sig_Handler_2 (fruity, 9, 8) with count = 1
waiting for SIGINT or SIGQUIT
^\
signal Quit occurred in Sig_Handler_1 (howdy, 3, 1) with count = 2
shutting down SIGQUIT in Sig_Handler_1 (howdy, 3, 1)
signal Quit occurred in Sig_Handler_1 (doody, 5, 4) with count = 2
shutting down SIGQUIT in Sig_Handler_1 (doody, 5, 4)
signal Quit occurred in Sig_Handler_2 (tutty, 7, 6) with count = 2
shutting down SIGQUIT in Sig_Handler_2 (tutty, 7, 6)
signal Quit occurred in Sig_Handler_2 (fruity, 9, 8) with count = 2
shutting down SIGQUIT in Sig_Handler_2 (fruity, 9, 8)
waiting for SIGINT or SIGQUIT
^C
signal Interrupt occurred in external handler!
signal Interrupt occurred in Sig_Handler_2 (tutty, 7, 6) with count = 3
signal Interrupt occurred in Sig_Handler_2 (fruity, 9, 8) with count = 3
waiting for SIGINT or SIGQUIT
^\Quit (core dumped)
When this test begins all four handlers are registered and
dispatched when a SIGINT or SIGQUIT occurs. After the
first SIGINT, the handle_signal method of the Sig_Handler_1
objects unregister themselves. At that point there are 4
SIGQUIT handlers left, but only 2 of our SIGINT handlers
left (and the 1 external handler). After the first
SIGQUIT, there are no SIGQUIT handlers left since they all
deregister themselves (which restores the "SIG_DFL"
disposition). On the second SIGINT there are only 3
handlers left (2 of ours and 1 external). Finally, on the
second SIGQUIT we exit and dump core since that's what
happens with the default disposition for SIGQUIT. */
#include "ace/Reactor.h"
#include "ace/WFMO_Reactor.h"
#include "ace/Select_Reactor.h"
#include "ace/Log_Msg.h"
#include "ace/Signal.h"
class Sig_Handler_1 : public ACE_Event_Handler
{
public:
Sig_Handler_1 (ACE_Reactor &reactor, const char *msg)
: msg_ (msg),
count_ (0),
reactor_ (reactor)
{
// Register the signal handlers.
this->quit_sigkey_ =
reactor.register_handler (SIGQUIT, this);
this->int_sigkey_ =
reactor.register_handler (SIGINT, this);
if (this->quit_sigkey_ == -1 || this->int_sigkey_ == -1)
ACE_ERROR ((LM_ERROR,
"%p\n",
"register_handler"));
}
// @@ Note that this code is not portable to all OS platforms since
// it does print statements within the signal handler.
virtual int handle_signal (int signum,
siginfo_t *,
ucontext_t *)
{
this->count_++;
ACE_DEBUG ((LM_DEBUG,
"\nsignal %S occurred in Sig_Handler_1 (%s, %d, %d) with count = %d",
signum,
this->msg_,
this->int_sigkey_,
this->quit_sigkey_,
this->count_));
if (this->count_ != 1 && signum == SIGQUIT)
{
if (this->reactor_.remove_handler (SIGQUIT,
0,
0,
this->quit_sigkey_) == -1)
ACE_ERROR ((LM_ERROR,
"\n%p",
"remove_handler"));
else
ACE_DEBUG ((LM_DEBUG,
"\nshutting down SIGQUIT in Sig_Handler_1 (%s, %d, %d)",
this->msg_,
this->int_sigkey_,
this->quit_sigkey_));
}
else if (this->count_ != 2 && signum == SIGINT)
{
if (this->reactor_.remove_handler (SIGINT,
0,
0,
this->int_sigkey_) == -1)
ACE_ERROR ((LM_ERROR,
"\n%p",
"remove_handler"));
else
ACE_DEBUG ((LM_DEBUG,
"\nshutting down SIGINT in Sig_Handler_1 (%s, %d, %d)",
this->msg_,
this->int_sigkey_,
this->quit_sigkey_));
}
return 0;
}
protected:
const char *msg_;
int count_;
int int_sigkey_;
int quit_sigkey_;
ACE_Reactor &reactor_;
};
class Sig_Handler_2 : public Sig_Handler_1
{
public:
Sig_Handler_2 (ACE_Reactor &reactor, const char *msg)
: Sig_Handler_1 (reactor, msg)
{
}
virtual int handle_signal (int signum,
siginfo_t *,
ucontext_t *)
{
this->count_++;
ACE_DEBUG ((LM_DEBUG,
"\nsignal %S occurred in Sig_Handler_2 (%s, %d, %d) with count = %d",
signum,
this->msg_,
this->int_sigkey_,
this->quit_sigkey_,
this->count_));
if (this->count_ != 0 && signum == SIGQUIT)
{
if (this->reactor_.remove_handler (SIGQUIT, 0, 0, this->quit_sigkey_) == -1)
ACE_ERROR ((LM_ERROR,
"\n%p",
"remove_handler"));
else
ACE_DEBUG ((LM_DEBUG,
"\nshutting down SIGQUIT in Sig_Handler_2 (%s, %d, %d)",
this->msg_,
this->int_sigkey_,
this->quit_sigkey_));
}
return 0;
}
};
static void
external_handler (int signum)
{
ACE_DEBUG ((LM_DEBUG,
"\nsignal %S occurred in external handler!",
signum));
}
int
ACE_TMAIN (int argc, ACE_TCHAR *[])
{
// If argc > 1 then allow multiple handlers per-signal, else just
// allow 1 handler per-signal.
ACE_Sig_Handlers multi_handlers;
#if defined (ACE_WIN32)
ACE_WFMO_Reactor reactor_impl (argc > 1
? &multi_handlers
: (ACE_Sig_Handler *) 0);
#else
ACE_Select_Reactor reactor_impl (argc > 1
? &multi_handlers
: (ACE_Sig_Handler *) 0);
#endif /* ACE_WIN32 */
ACE_Reactor reactor (&reactor_impl);
if (argc > 1)
{
// Register an "external" signal handler so that the
// ACE_Sig_Handlers code will have something to incorporate!
ACE_SignalHandler eh = (ACE_SignalHandler) external_handler;
ACE_Sig_Action sa (eh);
sa.register_action (SIGINT);
}
// Create a bevy of handlers.
Sig_Handler_1 h1 (reactor, "howdy");
Sig_Handler_1 h2 (reactor, "doody");
Sig_Handler_2 h3 (reactor, "tutty");
Sig_Handler_2 h4 (reactor, "fruity");
// Wait for user to type SIGINT and SIGQUIT.
for (;;)
{
ACE_DEBUG ((LM_DEBUG,
"\nwaiting for SIGINT or SIGQUIT\n"));
if (reactor.handle_events () == -1)
ACE_ERROR ((LM_ERROR,
"%p\n",
"handle_events"));
}
ACE_NOTREACHED (return 0);
}
|