diff options
Diffstat (limited to 'ACE/examples/Reactor/Proactor/test_aiosig_ace.cpp')
-rw-r--r-- | ACE/examples/Reactor/Proactor/test_aiosig_ace.cpp | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/ACE/examples/Reactor/Proactor/test_aiosig_ace.cpp b/ACE/examples/Reactor/Proactor/test_aiosig_ace.cpp new file mode 100644 index 00000000000..34c1b9b5ab2 --- /dev/null +++ b/ACE/examples/Reactor/Proactor/test_aiosig_ace.cpp @@ -0,0 +1,358 @@ +// $Id$ + +// ============================================================================ +// +// = FILENAME +// test_aiosig_sig.cpp +// +// = DESCRITPTION +// This program helps you to test the <aio_*> calls on a +// platform. +// Before running this test, make sure the platform can +// support POSIX <aio_> calls, using ACE_ROOT/tests/Aio_Plaform_Test.cpp +// +// This program tests the Signal based completion approach which +// uses <sigtimedwait> for completion querying. +// If this test is successful, ACE_POSIX_SIG_PROACTOR +// can be used on this platform. +// +// This program is a ACE version of the +// $ACE_ROOT/examples/Reactor/Proactor/test_aiosig.cpp, with +// ACE_DEBUGs and Message_Blocks. +// +// This test does the following: +// Issue two <aio_read>s. +// Assign SIGRTMIN as the notification signal. +// Mask these signals from delivery. +// Receive this signal by doing <sigtimedwait>. +// Wait for two completions (two signals) +// +// = COMPILATION +// make +// +// = RUN +// ./test_aiosig_ace +// +// = AUTHOR +// Programming for the Real World. Bill O. GallMeister. +// Modified by Alexander Babu Arulanthu <alex@cs.wustl.edu> +// +// ===================================================================== + +#include "ace/Message_Block.h" +#include "ace/Log_Msg.h" +#include "ace/os_include/os_aio.h" +#include "ace/OS_NS_signal.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_fcntl.h" +#include "ace/Asynch_IO.h" // for ACE_INFINITE + +static ACE_HANDLE file_handle = ACE_INVALID_HANDLE; +static ACE_Message_Block mb1 (BUFSIZ + 1); +static ACE_Message_Block mb2 (BUFSIZ + 1); +static aiocb aiocb1; +static aiocb aiocb2; +static aiocb aiocb3; +static sigset_t completion_signal; + +// Function prototypes. +static int setup_signal_delivery (void); +static int issue_aio_calls (void); +static int query_aio_completions (void); +static int test_aio_calls (void); +static void null_handler (int signal_number, siginfo_t *info, void *context); +static int setup_signal_handler (int signal_number); + +static int +setup_signal_delivery (void) +{ + // = Mask all the signals. + + sigset_t full_set; + + // Get full set. + if (sigfillset (&full_set) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Error:(%P | %t):%p\n", + "sigfillset failed"), + -1); + + // Mask them. + if (ACE_OS::pthread_sigmask (SIG_SETMASK, &full_set, 0) != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Error:(%P | %t):%p\n", + "pthread_sigmask failed"), + -1); + + // = Make a mask with SIGRTMIN only. We use only that signal to + // issue <aio_>'s. + + if (sigemptyset (&completion_signal) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n", + "Couldnt init the RT completion signal set"), + -1); + + if (sigaddset (&completion_signal, + SIGRTMIN) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n", + "Couldnt init the RT completion signal set"), + -1); + + // Set up signal handler for this signal. + return setup_signal_handler (SIGRTMIN); +} + +static int +setup_signal_handler (int signal_number) +{ + ACE_UNUSED_ARG (signal_number); + + // Setting up the handler(!) for these signals. + struct sigaction reaction; + sigemptyset (&reaction.sa_mask); // Nothing else to mask. + reaction.sa_flags = SA_SIGINFO; // Realtime flag. +#if defined (SA_SIGACTION) + // Lynx says, it is better to set this bit to be portable. + reaction.sa_flags &= SA_SIGACTION; +#endif /* SA_SIGACTION */ + reaction.sa_sigaction = null_handler; // Null handler. + int sigaction_return = sigaction (SIGRTMIN, + &reaction, + 0); + if (sigaction_return == -1) + ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n", + "Proactor couldnt do sigaction for the RT SIGNAL"), + -1); + return 0; +} + + +static int +issue_aio_calls (void) +{ + // Setup AIOCB. + aiocb1.aio_fildes = file_handle; + aiocb1.aio_offset = 0; + aiocb1.aio_buf = mb1.wr_ptr (); + aiocb1.aio_nbytes = BUFSIZ; + aiocb1.aio_reqprio = 0; + aiocb1.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + aiocb1.aio_sigevent.sigev_signo = SIGRTMIN; + aiocb1.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb1; + + // Fire off the aio read. + if (aio_read (&aiocb1) == -1) + // Queueing failed. + ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n", + "Asynch_Read_Stream: aio_read queueing failed"), + -1); + + // Setup AIOCB. + aiocb2.aio_fildes = file_handle; + aiocb2.aio_offset = BUFSIZ + 1; + aiocb2.aio_buf = mb2.wr_ptr (); + aiocb2.aio_nbytes = BUFSIZ; + aiocb2.aio_reqprio = 0; + aiocb2.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + aiocb2.aio_sigevent.sigev_signo = SIGRTMIN; + aiocb2.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb2; + + // Fire off the aio read. + if (aio_read (&aiocb2) == -1) + // Queueing failed. + ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n", + "Asynch_Read_Stream: aio_read queueing failed"), + -1); + + // Setup sigval. + aiocb3.aio_fildes = ACE_INVALID_HANDLE; + aiocb3.aio_offset = 0; + aiocb3.aio_buf = 0; + aiocb3.aio_nbytes = 0; + aiocb3.aio_reqprio = 0; + aiocb3.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + aiocb3.aio_sigevent.sigev_signo = SIGRTMIN; + aiocb3.aio_sigevent.sigev_value.sival_ptr = (void *) &aiocb3; + sigval value; + value.sival_ptr = reinterpret_cast<void *> (&aiocb3); + // Queue this one for completion right now. + if (sigqueue (ACE_OS::getpid (), SIGRTMIN, value) == -1) + // Queueing failed. + ACE_ERROR_RETURN ((LM_ERROR, + "Error: %p\n", "sigqueue"), + -1); + + return 0; +} + +static int +query_aio_completions (void) +{ + for (size_t number_of_compleions = 0; + number_of_compleions < 3; + number_of_compleions ++) + { + // Wait for <milli_seconds> amount of time. @@ Assigning + // <milli_seconds> to tv_sec. + timespec timeout; + timeout.tv_sec = ACE_INFINITE; + timeout.tv_nsec = 0; + + // To get back the signal info. + siginfo_t sig_info; + + // Await the RT completion signal. + int sig_return = sigtimedwait (&completion_signal, + &sig_info, + &timeout); + + // Error case. + // If failure is coz of timeout, then return *0* but set + // errno appropriately. This is what the WinNT proactor + // does. + if (sig_return == -1) + ACE_ERROR_RETURN ((LM_ERROR, "Error: %p\n", + "Error waiting for RT completion signals"), + -1); + + // RT completion signals returned. + if (sig_return != SIGRTMIN) + ACE_ERROR_RETURN ((LM_ERROR, + "Unexpected signal (%d) has been received while waiting for RT Completion Signals\n", + sig_return), + -1); + + // @@ Debugging. + ACE_DEBUG ((LM_DEBUG, + "Sig number found in the sig_info block : %d\n", + sig_info.si_signo)); + + // Is the signo returned consistent? + if (sig_info.si_signo != sig_return) + ACE_ERROR_RETURN ((LM_ERROR, + "Inconsistent signal number (%d) in the signal info block\n", + sig_info.si_signo), + -1); + + // @@ Debugging. + ACE_DEBUG ((LM_DEBUG, + "Signal code for this signal delivery : %d\n", + sig_info.si_code)); + + // Is the signal code an aio completion one? + if ((sig_info.si_code != SI_ASYNCIO) && + (sig_info.si_code != SI_QUEUE)) + ACE_ERROR_RETURN ((LM_DEBUG, + "Unexpected signal code (%d) returned on completion querying\n", + sig_info.si_code), + -1); + + // Retrive the aiocb. + aiocb* aiocb_ptr = (aiocb *) sig_info.si_value.sival_ptr; + if (aiocb_ptr == &aiocb3) + { + ACE_ASSERT (sig_info.si_code == SI_QUEUE); + ACE_DEBUG ((LM_DEBUG, "sigqueue caught... good\n")); + } + else + { + // Analyze error and return values. Return values are + // actually <errno>'s associated with the <aio_> call + // corresponding to aiocb_ptr. + int error_code = aio_error (aiocb_ptr); + if (error_code == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", + "Invalid control block was sent to <aio_error> for completion querying"), + -1); + + if (error_code != 0) + // Error occurred in the <aio_>call. Return the errno + // corresponding to that <aio_> call. + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", + "An AIO call has failed"), + error_code); + + // No error occured in the AIO operation. + int nbytes = aio_return (aiocb_ptr); + if (nbytes == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", + "Invalid control block was send to <aio_return>"), + -1); + if (number_of_compleions == 0) + { + // Print the buffer. + ACE_DEBUG ((LM_DEBUG, + "\n Number of bytes transferred : %d\n", + nbytes)); + // Note... the dumps of the buffers are disabled because they + // may easily overrun the ACE_Log_Msg output buffer. If you need + // to turn the on for some reason, be careful of this. +#if 0 + ACE_DEBUG ((LM_DEBUG, "The buffer : %s \n", mb1.rd_ptr ())); +#endif /* 0 */ + } + else + { + // Print the buffer. + ACE_DEBUG ((LM_DEBUG, + "\n Number of bytes transferred : %d\n", + nbytes)); +#if 0 + ACE_DEBUG ((LM_DEBUG, "The buffer : %s \n", mb2.rd_ptr ())); +#endif /* 0 */ + } + } + } + + return 0; +} + +static int +test_aio_calls (void) +{ + // Set up the input file. + // Open file (in SEQUENTIAL_SCAN mode) + file_handle = ACE_OS::open ("test_aiosig_ace.cpp", + O_RDONLY); + + if (file_handle == ACE_INVALID_HANDLE) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_OS::open"), + -1); + + if (setup_signal_delivery () == -1) + return -1; + + if (issue_aio_calls () == -1) + return -1; + + if (query_aio_completions () == -1) + return -1; + + return 0; +} + +static void +null_handler (int signal_number, + siginfo_t */* info */, + void * /* context */) +{ + ACE_ERROR ((LM_ERROR, + "Error:%s:Signal number %d\n" + "Mask all the RT signals for this thread", + "ACE_POSIX_SIG_Proactor::null_handler called", + signal_number)); +} + +int +main (int, char *[]) +{ + if (test_aio_calls () == 0) + printf ("RT SIG test successful:\n" + "ACE_POSIX_SIG_PROACTOR should work in this platform\n"); + else + printf ("RT SIG test failed:\n" + "ACE_POSIX_SIG_PROACTOR may not work in this platform\n"); + return 0; +} |