Merge branch 'master' into jwi-bcc64xsingletonwarning
[ACE_TAO.git] / ACE / examples / Reactor / Proactor / test_aiosig_ace.cpp
blob4e530b6abf705d4722ea32a3071bba30b8afa148
2 //=============================================================================
3 /**
4 * @file test_aiosig_ace.cpp
6 * This program helps you to test the <aio_*> calls on a
7 * platform.
8 * Before running this test, make sure the platform can
9 * support POSIX <aio_> calls, using ACE_ROOT/tests/Aio_Plaform_Test.cpp
10 * This program tests the Signal based completion approach which
11 * uses <sigtimedwait> for completion querying.
12 * If this test is successful, ACE_POSIX_SIG_PROACTOR
13 * can be used on this platform.
14 * This program is a ACE version of the
15 * $ACE_ROOT/examples/Reactor/Proactor/test_aiosig.cpp, with
16 * ACE_DEBUGs and Message_Blocks.
17 * This test does the following:
18 * Issue two <aio_read>s.
19 * Assign SIGRTMIN as the notification signal.
20 * Mask these signals from delivery.
21 * Receive this signal by doing <sigtimedwait>.
22 * Wait for two completions (two signals)
23 * make
24 * ./test_aiosig_ace
25 * @author Programming for the Real World. Bill O. GallMeister. Modified by Alexander Babu Arulanthu <alex@cs.wustl.edu>
27 //=============================================================================
30 #include "ace/Message_Block.h"
31 #include "ace/Log_Msg.h"
32 #include "ace/os_include/os_aio.h"
33 #include "ace/OS_NS_signal.h"
34 #include "ace/OS_NS_unistd.h"
35 #include "ace/OS_NS_fcntl.h"
36 #include "ace/Asynch_IO.h" // for ACE_INFINITE
38 static ACE_HANDLE file_handle = ACE_INVALID_HANDLE;
39 static ACE_Message_Block mb1 (BUFSIZ + 1);
40 static ACE_Message_Block mb2 (BUFSIZ + 1);
41 static aiocb aiocb1;
42 static aiocb aiocb2;
43 static aiocb aiocb3;
44 static sigset_t completion_signal;
46 // Function prototypes.
47 static int setup_signal_delivery ();
48 static int issue_aio_calls ();
49 static int query_aio_completions ();
50 static int test_aio_calls ();
51 static void null_handler (int signal_number, siginfo_t *info, void *context);
52 static int setup_signal_handler (int signal_number);
54 static int
55 setup_signal_delivery ()
57 // = Mask all the signals.
59 sigset_t full_set;
61 // Get full set.
62 if (ACE_OS::sigfillset (&full_set) != 0)
63 ACE_ERROR_RETURN ((LM_ERROR,
64 "Error:(%P | %t):%p\n",
65 "sigfillset failed"),
66 -1);
68 // Mask them.
69 if (ACE_OS::pthread_sigmask (SIG_SETMASK, &full_set, 0) != 0)
70 ACE_ERROR_RETURN ((LM_ERROR,
71 "Error:(%P | %t):%p\n",
72 "pthread_sigmask failed"),
73 -1);
75 // = Make a mask with SIGRTMIN only. We use only that signal to
76 // issue <aio_>'s.
78 if (ACE_OS::sigemptyset (&completion_signal) == -1)
79 ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n",
80 "Couldnt init the RT completion signal set"),
81 -1);
83 if (ACE_OS::sigaddset (&completion_signal,
84 SIGRTMIN) == -1)
85 ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n",
86 "Couldnt init the RT completion signal set"),
87 -1);
89 // Set up signal handler for this signal.
90 return setup_signal_handler (SIGRTMIN);
93 static int
94 setup_signal_handler (int signal_number)
96 ACE_UNUSED_ARG (signal_number);
98 // Setting up the handler(!) for these signals.
99 struct sigaction reaction;
100 ACE_OS::sigemptyset (&reaction.sa_mask); // Nothing else to mask.
101 reaction.sa_flags = SA_SIGINFO; // Realtime flag.
102 #if defined (SA_SIGACTION)
103 // Lynx says, it is better to set this bit to be portable.
104 reaction.sa_flags &= SA_SIGACTION;
105 #endif /* SA_SIGACTION */
106 reaction.sa_sigaction = null_handler; // Null handler.
107 int sigaction_return = ACE_OS::sigaction (SIGRTMIN,
108 &reaction,
110 if (sigaction_return == -1)
111 ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n",
112 "Proactor couldnt do sigaction for the RT SIGNAL"),
113 -1);
114 return 0;
118 static int
119 issue_aio_calls ()
121 // Setup AIOCB.
122 aiocb1.aio_fildes = file_handle;
123 aiocb1.aio_offset = 0;
124 aiocb1.aio_buf = mb1.wr_ptr ();
125 aiocb1.aio_nbytes = BUFSIZ;
126 aiocb1.aio_reqprio = 0;
127 aiocb1.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
128 aiocb1.aio_sigevent.sigev_signo = SIGRTMIN;
129 aiocb1.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb1;
131 // Fire off the aio read.
132 if (aio_read (&aiocb1) == -1)
133 // Queueing failed.
134 ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n",
135 "Asynch_Read_Stream: aio_read queueing failed"),
136 -1);
138 // Setup AIOCB.
139 aiocb2.aio_fildes = file_handle;
140 aiocb2.aio_offset = BUFSIZ + 1;
141 aiocb2.aio_buf = mb2.wr_ptr ();
142 aiocb2.aio_nbytes = BUFSIZ;
143 aiocb2.aio_reqprio = 0;
144 aiocb2.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
145 aiocb2.aio_sigevent.sigev_signo = SIGRTMIN;
146 aiocb2.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb2;
148 // Fire off the aio read.
149 if (aio_read (&aiocb2) == -1)
150 // Queueing failed.
151 ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n",
152 "Asynch_Read_Stream: aio_read queueing failed"),
153 -1);
155 // Setup sigval.
156 aiocb3.aio_fildes = ACE_INVALID_HANDLE;
157 aiocb3.aio_offset = 0;
158 aiocb3.aio_buf = 0;
159 aiocb3.aio_nbytes = 0;
160 aiocb3.aio_reqprio = 0;
161 aiocb3.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
162 aiocb3.aio_sigevent.sigev_signo = SIGRTMIN;
163 aiocb3.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb3;
164 sigval value;
165 value.sival_ptr = reinterpret_cast<void *> (&aiocb3);
166 // Queue this one for completion right now.
167 if (sigqueue (ACE_OS::getpid (), SIGRTMIN, value) == -1)
168 // Queueing failed.
169 ACE_ERROR_RETURN ((LM_ERROR,
170 "Error: %p\n", "sigqueue"),
171 -1);
173 return 0;
176 static int
177 query_aio_completions ()
179 for (size_t number_of_compleions = 0;
180 number_of_compleions < 3;
181 number_of_compleions ++)
183 // Wait for <milli_seconds> amount of time. @@ Assigning
184 // <milli_seconds> to tv_sec.
185 timespec timeout;
186 timeout.tv_sec = ACE_INFINITE;
187 timeout.tv_nsec = 0;
189 // To get back the signal info.
190 siginfo_t sig_info;
192 // Await the RT completion signal.
193 int sig_return = ACE_OS::sigtimedwait (&completion_signal,
194 &sig_info,
195 &timeout);
197 // Error case.
198 // If failure is coz of timeout, then return *0* but set
199 // errno appropriately. This is what the WinNT proactor
200 // does.
201 if (sig_return == -1)
202 ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n",
203 "Error waiting for RT completion signals"),
204 -1);
206 //FUZZ: disable check_for_lack_ACE_OS
207 // RT completion signals returned.
208 if (sig_return != SIGRTMIN)
209 ACE_ERROR_RETURN ((LM_ERROR,
210 "Unexpected signal (%d) has been received while waiting for RT Completion Signals\n",
211 sig_return),
212 -1);
213 //FUZZ: enble check_for_lack_ACE_OS
215 // @@ Debugging.
216 ACE_DEBUG ((LM_DEBUG,
217 "Sig number found in the sig_info block : %d\n",
218 sig_info.si_signo));
220 // Is the signo returned consistent?
221 if (sig_info.si_signo != sig_return)
222 ACE_ERROR_RETURN ((LM_ERROR,
223 "Inconsistent signal number (%d) in the signal info block\n",
224 sig_info.si_signo),
225 -1);
227 // @@ Debugging.
228 ACE_DEBUG ((LM_DEBUG,
229 "Signal code for this signal delivery : %d\n",
230 sig_info.si_code));
232 // Is the signal code an aio completion one?
233 if ((sig_info.si_code != SI_ASYNCIO) &&
234 (sig_info.si_code != SI_QUEUE))
235 ACE_ERROR_RETURN ((LM_DEBUG,
236 "Unexpected signal code (%d) returned on completion querying\n",
237 sig_info.si_code),
238 -1);
240 // Retrive the aiocb.
241 aiocb* aiocb_ptr = (aiocb *) sig_info.si_value.sival_ptr;
242 if (aiocb_ptr == &aiocb3)
244 ACE_ASSERT (sig_info.si_code == SI_QUEUE);
245 ACE_DEBUG ((LM_DEBUG, "sigqueue caught... good\n"));
247 else
249 // Analyze error and return values. Return values are
250 // actually <errno>'s associated with the <aio_> call
251 // corresponding to aiocb_ptr.
252 int error_code = aio_error (aiocb_ptr);
253 if (error_code == -1)
254 ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
255 "Invalid control block was sent to <aio_error> for completion querying"),
256 -1);
258 if (error_code != 0)
259 // Error occurred in the <aio_>call. Return the errno
260 // corresponding to that <aio_> call.
261 ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
262 "An AIO call has failed"),
263 error_code);
265 // No error occurred in the AIO operation.
266 int nbytes = aio_return (aiocb_ptr);
267 if (nbytes == -1)
268 ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
269 "Invalid control block was send to <aio_return>"),
270 -1);
271 if (number_of_compleions == 0)
273 // Print the buffer.
274 ACE_DEBUG ((LM_DEBUG,
275 "\n Number of bytes transferred : %d\n",
276 nbytes));
277 // Note... the dumps of the buffers are disabled because they
278 // may easily overrun the ACE_Log_Msg output buffer. If you need
279 // to turn the on for some reason, be careful of this.
280 #if 0
281 ACE_DEBUG ((LM_DEBUG, "The buffer : %s\n", mb1.rd_ptr ()));
282 #endif /* 0 */
284 else
286 // Print the buffer.
287 ACE_DEBUG ((LM_DEBUG,
288 "\n Number of bytes transferred : %d\n",
289 nbytes));
290 #if 0
291 ACE_DEBUG ((LM_DEBUG, "The buffer : %s\n", mb2.rd_ptr ()));
292 #endif /* 0 */
297 return 0;
300 static int
301 test_aio_calls ()
303 // Set up the input file.
304 // Open file (in SEQUENTIAL_SCAN mode)
305 file_handle = ACE_OS::open ("test_aiosig_ace.cpp",
306 O_RDONLY);
308 if (file_handle == ACE_INVALID_HANDLE)
309 ACE_ERROR_RETURN ((LM_ERROR,
310 "%p\n",
311 "ACE_OS::open"),
312 -1);
314 if (setup_signal_delivery () == -1)
315 return -1;
317 if (issue_aio_calls () == -1)
318 return -1;
320 if (query_aio_completions () == -1)
321 return -1;
323 return 0;
326 static void
327 null_handler (int signal_number,
328 siginfo_t */* info */,
329 void * /* context */)
331 ACE_ERROR ((LM_ERROR,
332 "Error:%s:Signal number %d\n"
333 "Mask all the RT signals for this thread",
334 "ACE_POSIX_SIG_Proactor::null_handler called",
335 signal_number));
339 ACE_TMAIN (int, ACE_TCHAR *[])
341 if (test_aio_calls () == 0)
342 ACE_OS::printf ("RT SIG test successful:\n"
343 "ACE_POSIX_SIG_PROACTOR should work in this platform\n");
344 else
345 ACE_OS::printf ("RT SIG test failed:\n"
346 "ACE_POSIX_SIG_PROACTOR may not work in this platform\n");
347 return 0;