//============================================================================= /** * @file Reactor_Exceptions_Test.cpp * * This is a test that makes sure the works * correctly in the face of C++ exceptions and threads. * * @author Luca Priorelli and Douglas C. Schmidt */ //============================================================================= #include "test_config.h" #include "ace/Reactor.h" #include "ace/SOCK_Dgram.h" #include "ace/INET_Addr.h" #include "ace/Thread_Manager.h" #include "ace/Select_Reactor.h" // Just need a simple exception class. class Except {}; static void throw_exception () { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) throw exception\n"))); throw Except (); } class My_Handler : public ACE_Event_Handler, public ACE_SOCK_Dgram { public: My_Handler (const ACE_INET_Addr &local_addr); ACE_HANDLE get_handle () const override; int handle_input (ACE_HANDLE handle) override; }; My_Handler::My_Handler (const ACE_INET_Addr &local_addr) : ACE_SOCK_Dgram (local_addr) { } ACE_HANDLE My_Handler::get_handle () const { return ACE_SOCK_Dgram::get_handle (); } int My_Handler::handle_input (ACE_HANDLE) { ACE_TCHAR buf[BUFSIZ]; ACE_INET_Addr from_addr; ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Activity occurred on handle %d!\n"), ACE_SOCK_Dgram::get_handle ())); ssize_t n = ACE_SOCK_Dgram::recv (buf, sizeof buf, from_addr); if (n == -1) ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("handle_input"))); else ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("got buf = %s\n"), buf)); throw_exception (); return 0; } class My_Reactor : public ACE_Select_Reactor { public: int handle_events (ACE_Time_Value *max_wait_time) override { int ret = 0; try { ret = ACE_Select_Reactor::handle_events (max_wait_time); } catch (...) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) catch exception\n"))); ret = -1; // do your thing, etc. } return ret; } int handle_events (ACE_Time_Value &max_wait_time) override { return this->handle_events (&max_wait_time); } }; #if defined (ACE_HAS_THREADS) static void* worker (void*) { ACE_Reactor::instance ()->owner (ACE_OS::thr_self ()); for (;;) if (ACE_Reactor::instance ()->handle_events () == -1) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) exception return\n"))); break; } return 0; } #endif /* ACE_HAS_THREADS */ int run_main (int argc, ACE_TCHAR *argv[]) { ACE_START_TEST (ACE_TEXT ("Reactor_Exceptions_Test")); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Starting tracing\n"))); u_short port = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT; ACE_INET_Addr local_addr (port); ACE_INET_Addr remote_addr (port, ACE_LOCALHOST, PF_INET); ACE_Reactor reactor (new My_Reactor, true); ACE_Reactor::instance (&reactor); ACE_Thread_Manager *thr_mgr = ACE_Thread_Manager::instance (); { // Make sure handler gets cleaned up before reactor by putting it in its // own scope My_Handler handler (local_addr); if (ACE_Reactor::instance ()->register_handler (&handler, ACE_Event_Handler::READ_MASK) == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("register_handler")), -1); #if defined (ACE_HAS_THREADS) thr_mgr->spawn (ACE_THR_FUNC (worker)); #else // Need to figure out how to implement this test. ACE_ERROR ((LM_INFO, ACE_TEXT ("threads not supported on this platform\n"))); #endif /* ACE_HAS_THREADS */ ACE_SOCK_Dgram dgram (ACE_sap_any_cast (ACE_INET_Addr &), PF_INET); for (size_t i = 0; i < ACE_MAX_ITERATIONS; i++) dgram.send (ACE_TEXT ("Hello"), sizeof (ACE_TEXT ("Hello")), remote_addr); // Barrier to wait for the other thread to return. thr_mgr->wait (); handler.close (); dgram.close (); } ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) exiting main\n"))); ACE_END_TEST; return 0; }