Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / tests / Bug_2815_Regression_Test.cpp
blob23baade0054d0928129446ef1b5c0580c80a75f6
1 /**
2 * @file Bug_2815_Regression_Test.cpp
4 * Verify that the notification queue can be used with large numbers
5 * of event handlers.
7 * Normally the ACE_Reactor uses a pipe to implement the notify()
8 * methods. ACE can be compiled with
9 * ACE_HAS_REACTOR_NOTIFICATION_QUEUE, with this configuration flag
10 * the Reactor uses a user-space queue to contain the notifications.
11 * A single message is sent through the pipe to indicate "pipe not
12 * empty."
14 * In this configuration, if an event handler is removed
15 * from the Reactor the user-space queue has to be searched for
16 * pending notifications and the notifications must be removed.
18 * The original implementation used a naive algorithm to search and
19 * remove the handlers, which resulted in very high overhead when
20 * removing handlers while having a very long notification queue.
22 * @author Carlos O'Ryan <coryan@atdesk.com>
25 #include "test_config.h"
26 #include "ace/Reactor.h"
27 #include "ace/TP_Reactor.h"
28 #include "ace/Select_Reactor.h"
30 class One_Shot_Handler;
32 /**
33 * @class Driver
35 * @brief Main driver for the test, generates notification events and
36 * verifies they are received correctly.
38 class Driver
40 public:
41 Driver(ACE_Reactor * reactor,
42 int max_notifications,
43 char const *test_name);
45 /// Run the test
46 void run ();
48 /// One of the sub-handlers has received a notification
49 void notification_received ();
51 /// One of the sub-handlers has decided to skip several notifications
52 void notifications_skipped (int skip_count);
54 /**
55 * @brief Return the reactor configured for this test
57 ACE_Reactor * reactor ();
59 private:
60 /**
61 * @brief Implement a single iteration.
63 * Each iteration of the test consists of sending multiple
64 * notifications simultaneously.
66 void send_notifications ();
68 /**
69 * @brief Return true if the test is finished.
71 bool done () const;
73 /**
74 * @brief Return true if there are more iterations to run.
76 bool more_iterations () const;
78 /**
79 * @brief Return true if the current iteration is completed.
81 bool current_iteration_done () const;
83 /**
84 * @brief Run one iteration of the test, each iteration doubles
85 * the number of events.
87 int run_one_iteration ();
89 /**
90 * @brief Initialize a bunch of One_Shot_Handlers
92 void initialize_handlers(
93 int nhandlers, One_Shot_Handler ** handlers);
95 /**
96 * @brief Dispatch events to the One_Shot_Handlers
98 void notify_handlers(
99 int nhandlers, One_Shot_Handler ** handlers);
102 * @brief Helpful for debugging
104 * The number of notifications received, skipped and sent are
105 * subject to simple invariants. During debugging any violation of
106 * those invariants indicates a problem in the application or the
107 * Reactor.
109 void check_notification_invariants();
111 /// A good place to set break points.
112 void invariant_failed();
114 private:
116 * @brief The reactor used in this test
118 ACE_Reactor * reactor_;
121 * @brief The maximum number of notifications in any single
122 * iteration.
124 int max_notifications_;
127 * @brief The name of the test
129 char const * test_name_;
132 * @brief Number of notifications received
134 int notifications_sent_;
137 * @brief Number of notifications sent
139 int notifications_recv_;
142 * @brief Number of notifications skipped because
143 * the handler was removed
145 int notifications_skipped_;
148 * @brief Number of notifications sent on each iteration
150 int notifications_curr_;
154 * @class One_Shot_Handler
156 * @brief A handler that removes itself from the reactor
157 * after its first notification.
159 * To demonstrate the problems with the first implementation of
160 * the notification queue we generate multiple event handlers.
161 * Then we generate multiple notifications for each, but the handlers
162 * remove themselves from the reactor when the first notification
163 * is delivered. This causes a lot of activity in the notification
164 * queue.
166 class One_Shot_Handler : public ACE_Event_Handler
168 public:
169 One_Shot_Handler(
170 Driver * master_handler,
171 char const * test_name,
172 int id);
174 /// Increase the number of expected notifications
175 void notification_queued();
177 /// Receive the notifications, but remove itself from the reactor on
178 /// on the first one.
179 int handle_exception(ACE_HANDLE) override;
181 private:
182 /// The driver for this test, communicate results to it
183 Driver * master_handler_;
185 /// The number of expected notifications
186 int expected_notifications_;
188 /// Identify the test and handler for debugging and better error output
189 char const * test_name_;
190 int id_;
194 run_main (int, ACE_TCHAR *[])
196 ACE_START_TEST (ACE_TEXT ("Bug_2815_Regression_Test"));
198 #if !defined(ACE_HAS_REACTOR_NOTIFICATION_QUEUE)
199 ACE_DEBUG ((LM_INFO,
200 ACE_TEXT ("Notification queue disabled. ")
201 ACE_TEXT ("This test depends on purge_pending_notifications. ")
202 ACE_TEXT ("Thus, the test is disabled in this case\n")));
204 #else
206 # ifdef ACE_LYNXOS_MAJOR
207 const int max_notifications = 512;
208 # else
209 const int max_notifications = 512 * 1024;
210 # endif
213 ACE_Reactor select_reactor (
214 new ACE_Select_Reactor,
217 Driver handler(&select_reactor,
218 max_notifications,
219 "Select_Reactor");
221 handler.run ();
225 ACE_Reactor tp_reactor (new ACE_TP_Reactor,
227 Driver handler(&tp_reactor,
228 max_notifications,
229 "TP_Reactor");
230 handler.run();
233 #endif /* ACE_HAS_THREADS */
234 ACE_END_TEST;
236 return 0;
239 Driver::Driver (
240 ACE_Reactor * reactor,
241 int max_notifications,
242 char const * test_name)
243 : reactor_(reactor)
244 , max_notifications_(max_notifications)
245 , test_name_(test_name)
246 , notifications_sent_(0)
247 , notifications_recv_(0)
248 , notifications_skipped_(0)
249 , notifications_curr_(1)
253 void
254 Driver::run ()
256 while(more_iterations())
258 if(run_one_iteration() == -1)
260 return;
263 notifications_curr_ *= 2;
266 ACE_DEBUG ((LM_INFO,
267 ACE_TEXT ("Test %C passed sent=%d, recv=%d, skip=%d\n"),
268 test_name_,
269 notifications_sent_,
270 notifications_recv_,
271 notifications_skipped_));
274 void
275 Driver::notification_received ()
277 ++notifications_recv_;
278 check_notification_invariants();
281 void
282 Driver::notifications_skipped (int skip_count)
284 notifications_skipped_ += skip_count;
285 check_notification_invariants();
288 ACE_Reactor *
289 Driver::reactor()
291 return reactor_;
294 void
295 Driver::send_notifications ()
297 int const nhandlers = 16;
298 One_Shot_Handler * handlers[nhandlers];
299 initialize_handlers(nhandlers, handlers);
301 for (int i = 0; i != notifications_curr_; ++i)
303 notify_handlers(nhandlers, handlers);
307 bool
308 Driver::done () const
310 return !more_iterations() && current_iteration_done();
313 bool
314 Driver::more_iterations() const
316 return notifications_curr_ < max_notifications_;
319 bool
320 Driver::current_iteration_done() const
322 return notifications_sent_ == (notifications_recv_ + notifications_skipped_);
326 Driver::run_one_iteration ()
328 ACE_DEBUG ((LM_INFO,
329 ACE_TEXT ("Running iteration with %d events for %C test\n"),
330 notifications_curr_,
331 test_name_));
333 send_notifications ();
335 // Run for 30 seconds or until the test is done.
337 ACE_Time_Value const timeout(30,0);
339 while (!current_iteration_done())
341 ACE_Time_Value start = ACE_OS::gettimeofday();
342 ACE_Time_Value interval(1,0);
343 reactor()->run_reactor_event_loop(interval);
344 ACE_Time_Value end = ACE_OS::gettimeofday();
346 if (end - start >= timeout)
348 ACE_ERROR ((LM_ERROR,
349 ACE_TEXT ("Test %C failed due to timeout ")
350 ACE_TEXT (" sent=%d,recv=%d,skip=%d\n"),
351 test_name_,
352 notifications_sent_,
353 notifications_recv_,
354 notifications_skipped_));
355 return -1;
359 return 0;
362 void
363 Driver::initialize_handlers(
364 int nhandlers, One_Shot_Handler ** handlers)
366 for (int j = 0; j != nhandlers; ++j)
368 handlers[j] = new One_Shot_Handler(this, test_name_, j);
372 void
373 Driver::notify_handlers(
374 int nhandlers, One_Shot_Handler ** handlers)
376 for(int i = 0; i != nhandlers; ++i)
378 if(reactor()->notify (handlers[i]) == -1)
380 ACE_ERROR((LM_ERROR,
381 ACE_TEXT ("notify %d/%d in %C %p\n"),
382 i, notifications_curr_, test_name_, ACE_TEXT ("test")));
383 return;
385 handlers[i]->notification_queued();
387 ++notifications_sent_;
391 void Driver::
392 check_notification_invariants()
394 if (notifications_sent_ < 0)
396 ACE_ERROR ((LM_ERROR,
397 ACE_TEXT("The number of notifications sent (%d)")
398 ACE_TEXT(" should be positive\n"),
399 notifications_sent_));
400 invariant_failed();
403 if (notifications_recv_ < 0)
405 ACE_ERROR ((LM_ERROR,
406 ACE_TEXT("The number of notifications received (%d)")
407 ACE_TEXT(" should be positive\n"),
408 notifications_recv_));
409 invariant_failed();
412 if (notifications_skipped_ < 0)
414 ACE_ERROR ((LM_ERROR,
415 ACE_TEXT("The number of notifications skipped (%d)")
416 ACE_TEXT(" should be positive\n"),
417 notifications_skipped_));
418 invariant_failed();
421 if (notifications_sent_ < notifications_recv_)
423 ACE_ERROR ((LM_ERROR,
424 ACE_TEXT("Too many notifications received (%d)")
425 ACE_TEXT(" vs sent (%d)\n"),
426 notifications_recv_, notifications_sent_));
427 invariant_failed();
430 if (notifications_sent_ < notifications_skipped_)
432 ACE_ERROR ((LM_ERROR,
433 ACE_TEXT("Too many notifications skipped (%d)")
434 ACE_TEXT(" vs sent (%d)\n"),
435 notifications_skipped_, notifications_sent_));
436 invariant_failed();
439 if (notifications_skipped_ + notifications_recv_ > notifications_sent_)
441 ACE_ERROR ((LM_ERROR,
442 ACE_TEXT("Too many notifications skipped (%d)")
443 ACE_TEXT(" and received (%d) vs sent (%d)\n"),
444 notifications_skipped_, notifications_recv_,
445 notifications_sent_));
446 invariant_failed();
450 void Driver::
451 invariant_failed()
453 // Just a good place to set a breakpoint
456 // ============================================
458 One_Shot_Handler::One_Shot_Handler(
459 Driver * master_handler,
460 char const * test_name, int id)
461 : ACE_Event_Handler(master_handler->reactor())
462 , master_handler_(master_handler)
463 , expected_notifications_(0)
464 , test_name_(test_name)
465 , id_(id)
469 void One_Shot_Handler::
470 notification_queued()
472 ++expected_notifications_;
475 int One_Shot_Handler::
476 handle_exception(ACE_HANDLE)
478 --expected_notifications_;
479 master_handler_->notification_received();
481 int r = reactor()->purge_pending_notifications(this);
482 if (r >= 0)
484 master_handler_->notifications_skipped(r);
485 delete this;
486 return 0;
489 ACE_ERROR((LM_ERROR,
490 ACE_TEXT ("Cannot remove handler %d in %C test\n"),
491 id_, test_name_));
493 delete this;
494 return 0;