summaryrefslogtreecommitdiff
path: root/examples/Reactor/Misc/signal_tester.cpp
blob: 37613f14f38a1cdd692bfc3305e504eb4200fd52 (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
// Perform an extensive test of the ACE_Reactor's event dispatching
// $Id$

// mechanisms.  These mechanisms illustrate how signals, I/O, and
// timeout events can all be handled within the same framework.  In
// addition, this example illustrates how to use the ACE_Reactor for
// devices that perform I/O via signals (such as SVR4 message queues).


#include "ace/Service_Config.h"

// Used to shut down the event loop.
static sig_atomic_t done = 0;

// This class illustrates how to handle signal-driven I/O using the
// ACE_Reactor framework.  Note that signals may be caught and
// processed without requiring the use of global signal handler
// functions or global signal handler data.

class Sig_Handler : public ACE_Event_Handler
{
public:
  Sig_Handler (void);
  virtual ACE_HANDLE get_handle (void) const;
  virtual int handle_input (ACE_HANDLE);
  virtual int shutdown (ACE_HANDLE, ACE_Reactor_Mask);
  virtual int handle_signal (ACE_HANDLE signum, siginfo_t * = 0, 
			     ucontext_t * = 0);

private:
  ACE_HANDLE handle_;
};

// A dummy_handle is required to reserve a slot in the ACE_Reactor's
// descriptor table.

Sig_Handler::Sig_Handler (void)
{
  // Assign the Sig_Handler a dummy I/O descriptor.  Note that even
  // though we open this file "Write Only" we still need to use the
  // ACE_Event_Handler::NULL_MASK when registering this with the
  // ACE_Reactor (see below).
  this->handle_ = ACE_OS::open (ACE_DEV_NULL, O_WRONLY);
  ACE_ASSERT (this->handle_ != -1);

  // Register signal handler object.  Note that NULL_MASK is used to
  // keep the ACE_Reactor from calling us back on the "/dev/null"
  // descriptor.
  if (ACE_Service_Config::reactor ()->register_handler 
      (this, ACE_Event_Handler::NULL_MASK) == -1)
    ACE_ERROR ((LM_ERROR, "%p\n%a", "register_handler", 1));

  // Create a sigset_t corresponding to the signals we want to catch.
  ACE_Sig_Set sig_set;

  sig_set.sig_add (SIGINT);
  sig_set.sig_add (SIGQUIT);
  sig_set.sig_add (SIGALRM);  

  // Register the signal handler object to catch the signals.
  if (ACE_Service_Config::reactor ()->register_handler (sig_set, this) == -1)
    ACE_ERROR ((LM_ERROR, "%p\n%a", "register_handler", 1));
}

// Called by the ACE_Reactor to extract the fd.

ACE_HANDLE
Sig_Handler::get_handle (void) const
{
  return this->handle_;
}

// In a real application, this method would be where the read on the
// signal-driven I/O device would occur asynchronously.  For now we'll
// just print a greeting to let you know that everything is working
// properly!

int 
Sig_Handler::handle_input (ACE_HANDLE)
{
  ACE_DEBUG ((LM_DEBUG, "handling asynchonrous input...\n"));
  return 0;
}

// In a real application, this method would do any cleanup activities
// required when shutting down the I/O device.

int 
Sig_Handler::shutdown (ACE_HANDLE, ACE_Reactor_Mask)
{
  ACE_DEBUG ((LM_DEBUG, "closing down Sig_Handler...\n"));
  return 0;
}

// This method handles all the signals that are being caught by this
// object.  In our simple example, we are simply catching SIGALRM,
// SIGINT, and SIGQUIT.  Anything else is logged and ignored.
//
// There are several advantages to using this approach.  First, 
// the behavior triggered by the signal is handled in the main event
// loop, rather than in the signal handler.  Second, the ACE_Reactor's 
// signal handling mechanism eliminates the need to use global signal 
// handler functions and data. 

int
Sig_Handler::handle_signal (int signum, siginfo_t *, ucontext_t *)
{
  ACE_DEBUG ((LM_DEBUG, "received signal %S\n", signum));

  switch (signum)
    {
    case SIGALRM:
      // Rearm the alarm.
      ACE_OS::alarm (4);
      break;
    case SIGINT:
      // Tell the ACE_Reactor to enable the ready bit for
      // this->handle_.  The ACE_Reactor will subsequently call the
      // Sig_Handler::handle_input method from within its event loop.
      return ACE_Service_Config::reactor ()->ready_ops 
	(this->handle_, ACE_Event_Handler::READ_MASK, ACE_Reactor::ADD_MASK);
    case SIGQUIT:
      ACE_DEBUG ((LM_DEBUG, "%S: shutting down signal tester\n", signum));
      ACE_Service_Config::end_reactor_event_loop ();
      break;
    default: 
      ACE_DEBUG ((LM_DEBUG, 
		  "%S: not handled, returning to program\n", signum));
      break;
    }
  return 0;
}

// This class illustrates that the ACE_Reactor can handle signals,
// STDIO, and timeouts using the same mechanisms.

class STDIN_Handler : public ACE_Event_Handler
{
public:
  STDIN_Handler (void);
  virtual int handle_input (ACE_HANDLE);
  virtual int handle_timeout (const ACE_Time_Value &, 
			      const void *arg);
};

STDIN_Handler::STDIN_Handler (void)
{
  if (ACE::register_stdin_handler (this,
				   ACE_Service_Config::reactor (),
				   ACE_Service_Config::thr_mgr ()) == -1)
    ACE_ERROR ((LM_ERROR, "%p\n", "register_stdin_handler"));

  // Register the STDIN_Handler to be dispatched once every second.
  else if (ACE_Service_Config::reactor ()->schedule_timer
	   (this, 0, ACE_Time_Value (1), ACE_Time_Value (1)) == -1)
    ACE_ERROR ((LM_ERROR, "%p\n%a", "schedule_timer", 1));
}

int 
STDIN_Handler::handle_timeout (const ACE_Time_Value &tv,
			       const void *)
{
  ACE_DEBUG ((LM_DEBUG, "timeout occurred at %d sec, %d usec\n",
	      tv.sec (), tv.usec ()));
  return 0;
}

// Read from input descriptor and write to stdout descriptor.

int 
STDIN_Handler::handle_input (ACE_HANDLE handle)
{
  ssize_t n;
  char buf[BUFSIZ];

  switch (n = ACE_OS::read (handle, buf, sizeof buf))
    {
    case -1:
      if (errno == EINTR)
	return 0;
        /* NOTREACHED */
      else
	ACE_ERROR ((LM_ERROR, "%p\n", "read"));
      /* FALLTHROUGH */
    case 0:
      ACE_Service_Config::end_reactor_event_loop ();
      break;
    default:
      {
	ssize_t result = ACE::write_n (ACE_STDOUT, buf, n);

	if (result != n)
	  ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "write"), 
			    result == -1 && errno == EINTR ? 0 : -1);
      }
    }
  return 0;
}

int
main (int argc, char *argv[])
{
  ACE_Service_Config daemon (argv [0]);

  // Signal handler.
  Sig_Handler sh;

  // Define an I/O handler object.
  STDIN_Handler ioh;

  // Optionally start the alarm.
  if (argc > 1)
    ACE_OS::alarm (4);

  // Loop handling signals and I/O events until SIGQUIT occurs.

  while (daemon.reactor_event_loop_done () == 0)
    daemon.run_reactor_event_loop ();

  return 0;
}