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
11 #include "test_config.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;
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
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;
44 void send_dummy_data();
46 /// Removes itself from the reactor on the next call to handle_input()
47 void simulate_socket_closure();
50 ACE_HANDLE
get_handle() const override
;
51 int handle_input(ACE_HANDLE
) override
;
54 bool auto_remove_flag_
;
56 size_t handle_input_count_
;
60 ACE_HANDLE handles_
[2];
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
74 //FUZZ: disable check_for_lack_ACE_OS
75 int open(ACE_Reactor
* reactor
);
77 //FUZZ: enable check_for_lack_ACE_OS
79 bool check_expected_results() const;
81 int handle_timeout(ACE_Time_Value
const &, void const*) override
;
84 void send_data_through_handlers();
85 void remove_some_handlers();
87 Handler
& special_handler();
88 Handler
const & special_handler() const;
91 Handler handler_
[nhandlers
];
94 size_t recorded_count_
;
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 std::unique_ptr
<ACE_Select_Reactor
> auto_impl (impl_ptr
);
110 ACE_Reactor
reactor (impl_ptr
);
112 // Create the timer, this is the main driver for the test
113 Timer
* timer
= new Timer
;
115 // Initialize the timer and register with the reactor
116 if (-1 == timer
->open (&reactor
))
118 ACE_ERROR_RETURN ((LM_ERROR
, "Cannot initialize timer\n"), -1);
121 reactor
.run_reactor_event_loop ();
123 // Verify that the results are what we expect
124 if (!timer
->check_expected_results ())
126 ACE_ERROR_RETURN ((LM_ERROR
, "Test failed\n"), -1);
139 : auto_remove_flag_(false)
140 , handle_input_count_(0)
145 int Handler::open(ACE_Reactor
* r
)
147 if(-1 == the_pipe_
.open(handles_
))
151 if(-1 == r
->register_handler(this, ACE_Event_Handler::READ_MASK
))
158 size_t Handler::handle_input_count() const
160 return handle_input_count_
;
163 void Handler::send_dummy_data()
165 char buf
[] = "dummy";
166 (void) the_pipe_
.send(buf
, sizeof(buf
));
169 void Handler::simulate_socket_closure()
171 auto_remove_flag_
= true;
174 ACE_HANDLE
Handler::get_handle() const
176 return the_pipe_
.read_handle();
179 int Handler::handle_input(ACE_HANDLE
/* h */)
181 ++handle_input_count_
;
182 // ACE_DEBUG((LM_DEBUG, "Handler::handle_input called for %d\n", h));
184 if(auto_remove_flag_
)
186 auto_remove_flag_
= false;
193 int const initial_iterations
= 5;
194 int const total_iterations
= 10;
196 int const special_handler_index
= nhandlers
- 1;
204 int Timer::open(ACE_Reactor
* r
)
208 // Initialize both handles and register them with the reactor for reading.
209 for(int i
= 0; i
!= nhandlers
; ++i
)
211 if (-1 == handler_
[i
].open(r
))
213 ACE_ERROR_RETURN ((LM_ERROR
, "Could not open dummy handler %d\n", i
), -1);
217 ACE_Time_Value
const interval(0, ACE_ONE_SECOND_IN_USECS
/ 10);
218 ACE_Time_Value
const startup (0, ACE_ONE_SECOND_IN_USECS
/ 20);
220 if ( -1 == r
->schedule_timer(this, 0, startup
, interval
))
222 ACE_ERROR_RETURN((LM_ERROR
, "Could not schedule timer\n"), -1);
230 for(int i
= 0; i
!= nhandlers
; ++i
)
232 reactor()->remove_handler(&handler_
[i
], ACE_Event_Handler::ALL_EVENTS_MASK
);
234 reactor()->cancel_timer(this);
237 bool Timer::check_expected_results() const
239 // We expect at least one more call after the other handlers are removed.
240 if(recorded_count_
+ 1 < special_handler().handle_input_count() )
247 int Timer::handle_timeout(ACE_Time_Value
const &, void const *)
251 // Sending data on the first iteration makes the handles always
252 // "ready" for reading because the Handler::handle_input() function
253 // never consumes the data.
254 send_data_through_handlers();
258 if (iteration_
< initial_iterations
)
260 // The first iterations are there just to prime things.
264 if (iteration_
== initial_iterations
)
266 // We expect the special_handler() to work normally after this
267 // iteration, i.e., more calls to handle_input() should be delivered
269 recorded_count_
= special_handler().handle_input_count();
271 // Remove the handlers the next time the loop runs
272 remove_some_handlers();
274 // Run the event loop, this causes the handlers to be removed from the
275 // reactor, except for special_handler()
276 ACE_Time_Value
interval(0, ACE_ONE_SECOND_IN_USECS
/ 50);
277 reactor()->handle_events(&interval
);
282 if (iteration_
< total_iterations
)
284 // Run a while more to make sure the special_handler() is used.
288 reactor()->end_reactor_event_loop();
293 void Timer::send_data_through_handlers()
295 for(int i
= 0; i
!= nhandlers
; ++i
)
297 handler_
[i
].send_dummy_data();
301 void Timer::remove_some_handlers()
303 for(int i
= 0; i
!= nhandlers
- 1; ++i
)
305 handler_
[i
].simulate_socket_closure();
309 Handler
& Timer::special_handler()
311 return handler_
[special_handler_index
];
314 Handler
const & Timer::special_handler() const
316 return handler_
[special_handler_index
];