Merge pull request #1844 from jrw972/monterey
[ACE_TAO.git] / ACE / tests / Bug_2540_Regression_Test.cpp
blob5cfc8a53303983661a2bcd0e048b84090d926c76
1 /**
2 * @file Bug_2540_Regression_Test.cpp
4 * Reproduces the problems reported in bug 2540
5 * http://bugzilla.dre.vanderbilt.edu/show_bug.cgi?id=2540
7 * @author Carlos O'Ryan <coryan@atdesk.com>
8 * Based on Bug_1890_Regression_Test
9 */
11 #include "test_config.h"
13 #include "ace/Pipe.h"
14 #include "ace/Event_Handler.h"
15 #include "ace/Reactor.h"
16 #include "ace/Select_Reactor.h"
17 #include "ace/Auto_Ptr.h"
19 int const nhandlers = 3;
21 /**
22 * This class is used to create real I/O in the test. To keep the I/O under
23 * control and keep the test to a single process we use ACE_Pipe. This class
24 * is known to work with the Reactor, in fact, that is its main function.
26 * Handler counts how many calls to handle_input() has the reactor performed.
27 * When bug 2540 is triggered the Reactor continues to call the timers, but it
28 * stops calling select() and the handle_input() functions.
30 class Handler : public ACE_Event_Handler
32 public:
33 Handler();
35 //FUZZ: disable check_for_lack_ACE_OS
36 /// Initialize the pipe and register with the reactor
37 int open(ACE_Reactor * reactor);
38 //FUZZ: enable check_for_lack_ACE_OS
40 /// Return the current count
41 size_t handle_input_count() const;
43 /// Write some data
44 void send_dummy_data();
46 /// Removes itself from the reactor on the next call to handle_input()
47 void simulate_socket_closure();
49 /// Reactor callback
50 virtual ACE_HANDLE get_handle() const;
51 virtual int handle_input(ACE_HANDLE);
53 private:
54 bool auto_remove_flag_;
56 size_t handle_input_count_;
58 ACE_Pipe the_pipe_;
60 ACE_HANDLE handles_[2];
63 /**
64 * This is the main driver for the test. This timer is called by the reactor
65 * in a repeating interval. On the first @c initial_iterations the Timer
66 * writes data through all of its handlers. On iteration @c initial_iteration
67 * it triggers bug 2540 by removing two handlers from the reactor.
69 class Timer : public ACE_Event_Handler
71 public:
72 Timer();
74 //FUZZ: disable check_for_lack_ACE_OS
75 int open(ACE_Reactor * reactor);
76 void close();
77 //FUZZ: enable check_for_lack_ACE_OS
79 bool check_expected_results() const;
81 virtual int handle_timeout(ACE_Time_Value const &, void const*);
83 private:
84 void send_data_through_handlers();
85 void remove_some_handlers();
87 Handler & special_handler();
88 Handler const & special_handler() const;
90 private:
91 Handler handler_[nhandlers];
92 int iteration_;
94 size_t recorded_count_;
97 int
98 run_main (int, ACE_TCHAR *[])
100 ACE_START_TEST (ACE_TEXT ("Bug_2540_Regression_Test"));
102 // Bug 2540 is all about ACE_Select_Reactor, so run it on that reactor
103 // regardless of platform. In particular, this test relies on a handler
104 // that doesn't consume ready-to-read data being called back - this won't
105 // happen with ACE_WFMO_Reactor.
106 ACE_Select_Reactor *impl_ptr = 0;
107 ACE_NEW_RETURN (impl_ptr, ACE_Select_Reactor, -1);
108 #if defined (ACE_HAS_CPP11)
109 std::unique_ptr<ACE_Select_Reactor> auto_impl (impl_ptr);
110 #else
111 auto_ptr<ACE_Select_Reactor> auto_impl (impl_ptr);
112 #endif
114 ACE_Reactor reactor (impl_ptr);
116 // Create the timer, this is the main driver for the test
117 Timer * timer = new Timer;
119 // Initialize the timer and register with the reactor
120 if (-1 == timer->open (&reactor))
122 ACE_ERROR_RETURN ((LM_ERROR, "Cannot initialize timer\n"), -1);
125 reactor.run_reactor_event_loop ();
127 // Verify that the results are what we expect
128 if (!timer->check_expected_results ())
130 ACE_ERROR_RETURN ((LM_ERROR, "Test failed\n"), -1);
133 // Cleanup
134 timer->close ();
135 delete timer;
137 ACE_END_TEST;
139 return 0;
142 Handler::Handler()
143 : auto_remove_flag_(false)
144 , handle_input_count_(0)
145 , the_pipe_()
149 int Handler::open(ACE_Reactor * r)
151 if(-1 == the_pipe_.open(handles_))
153 return -1;
155 if(-1 == r->register_handler(this, ACE_Event_Handler::READ_MASK))
157 return -1;
159 return 0;
162 size_t Handler::handle_input_count() const
164 return handle_input_count_;
167 void Handler::send_dummy_data()
169 char buf[] = "dummy";
170 (void) the_pipe_.send(buf, sizeof(buf));
173 void Handler::simulate_socket_closure()
175 auto_remove_flag_ = true;
178 ACE_HANDLE Handler::get_handle() const
180 return the_pipe_.read_handle();
183 int Handler::handle_input(ACE_HANDLE /* h */)
186 ++handle_input_count_;
187 // ACE_DEBUG((LM_DEBUG, "Handler::handle_input called for %d\n", h));
189 if(auto_remove_flag_)
191 auto_remove_flag_ = false;
192 return -1;
195 return 0;
198 int const initial_iterations = 5;
199 int const total_iterations = 10;
201 int const special_handler_index = nhandlers - 1;
203 Timer::Timer()
204 : iteration_(0)
205 , recorded_count_(0)
209 int Timer::open(ACE_Reactor * r)
211 this->reactor(r);
213 // Initialize both handles and register them with the reactor for reading.
214 for(int i = 0; i != nhandlers; ++i)
216 if (-1 == handler_[i].open(r))
218 ACE_ERROR_RETURN ((LM_ERROR, "Could not open dummy handler %d\n", i), -1);
222 ACE_Time_Value const interval(0, ACE_ONE_SECOND_IN_USECS / 10);
223 ACE_Time_Value const startup (0, ACE_ONE_SECOND_IN_USECS / 20);
225 if ( -1 == r->schedule_timer(this, 0, startup, interval))
227 ACE_ERROR_RETURN((LM_ERROR, "Could not schedule timer\n"), -1);
230 return 0;
233 void Timer::close()
235 for(int i = 0; i != nhandlers; ++i)
237 reactor()->remove_handler(&handler_[i], ACE_Event_Handler::ALL_EVENTS_MASK);
239 reactor()->cancel_timer(this);
242 bool Timer::check_expected_results() const
244 // We expect at least one more call after the other handlers are removed.
245 if(recorded_count_ + 1 < special_handler().handle_input_count() )
247 return true;
249 return false;
252 int Timer::handle_timeout(ACE_Time_Value const &, void const *)
254 if (iteration_ == 0)
256 // Sending data on the first iteration makes the handles always
257 // "ready" for reading because the Handler::handle_input() function
258 // never consumes the data.
259 send_data_through_handlers();
262 ++iteration_;
263 if (iteration_ < initial_iterations)
265 // The first iterations are there just to prime things.
266 return 0;
269 if (iteration_ == initial_iterations)
271 // We expect the special_handler() to work normally after this
272 // iteration, i.e., more calls to handle_input() should be delivered
273 // to it.
274 recorded_count_ = special_handler().handle_input_count();
276 // Remove the handlers the next time the loop runs
277 remove_some_handlers();
279 // Run the event loop, this causes the handlers to be removed from the
280 // reactor, except for special_handler()
281 ACE_Time_Value interval(0, ACE_ONE_SECOND_IN_USECS / 50);
282 reactor()->handle_events(&interval);
284 return 0;
287 if (iteration_ < total_iterations)
289 // Run a while more to make sure the special_handler() is used.
290 return 0;
293 reactor()->end_reactor_event_loop();
295 return 0;
298 void Timer::send_data_through_handlers()
300 for(int i = 0; i != nhandlers; ++i)
302 handler_[i].send_dummy_data();
306 void Timer::remove_some_handlers()
308 for(int i = 0; i != nhandlers - 1; ++i)
310 handler_[i].simulate_socket_closure();
314 Handler & Timer::special_handler()
316 return handler_[special_handler_index];
319 Handler const & Timer::special_handler() const
321 return handler_[special_handler_index];