Merge pull request #2309 from mitza-oci/warnings
[ACE_TAO.git] / ACE / tests / Reactor_Notify_Test.cpp
blobe317a659199ab4992b322d0465945da3da6500a8
2 //=============================================================================
3 /**
4 * @file Reactor_Notify_Test.cpp
6 * This is a test that illustrates how the <ACE_Reactor>'s
7 * <notify> method works under various <max_notify_iterations>
8 * settings. It also tests that the <disable_notify_pipe> option
9 * works correctly. Moreover, if the $ACE_ROOT/ace/config.h file
10 * has the ACE_HAS_REACTOR_NOTIFICATION_QUEUE option enabled this
11 * test will also exercise this feature.
13 * @author Douglas C. Schmidt <d.schmidt@vanderbilt.edu>
15 //=============================================================================
17 #include "test_config.h"
18 #include "ace/OS_NS_unistd.h"
19 #include "ace/Synch_Traits.h"
20 #include "ace/Task.h"
21 #include "ace/Pipe.h"
22 #include <memory>
23 #include "ace/Reactor.h"
24 #include "ace/Select_Reactor.h"
25 #include "ace/Thread_Semaphore.h"
27 #if defined (ACE_HAS_THREADS)
29 static const time_t LONG_TIMEOUT = 10;
30 static const time_t SHORT_TIMEOUT = 2;
32 // A class to run a quiet event loop in one thread, and a plain notify()
33 // from the main thread to make sure a simple notify will wake up a quiet
34 // reactor.
35 class Quiet_Notify_Tester : public ACE_Task<ACE_NULL_SYNCH>
37 public:
38 Quiet_Notify_Tester () : result_ (0) {}
39 ~Quiet_Notify_Tester () override { this->wait (); }
41 //FUZZ: disable check_for_lack_ACE_OS
42 /// Start the reactor event thread.
43 int open (void * = 0) override;
45 // Run the reactor event loop.
46 int svc () override;
48 // Return the test result, 0 ok, -1 fail
49 int result () const { return this->result_; }
51 private:
52 ACE_Reactor r_;
53 int result_;
56 int
57 Quiet_Notify_Tester::open (void *)
59 this->reactor (&this->r_);
60 return this->activate ();
63 int
64 Quiet_Notify_Tester::svc ()
66 // Count on the main thread doing a notify in less than LONG_TIMEOUT
67 // seconds. If we don't get it, report a failure.
68 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Starting quiet event loop\n")));
69 this->r_.owner (ACE_Thread::self ());
70 ACE_Time_Value tmo (LONG_TIMEOUT);
71 int status = this->r_.handle_events (&tmo);
72 time_t remain = tmo.sec ();
73 ACE_DEBUG ((LM_DEBUG,
74 ACE_TEXT ("(%t) event loop status %d, %: secs remain\n"),
75 status, remain));
76 if (remain == 0)
78 ACE_ERROR ((LM_ERROR,
79 ACE_TEXT ("(%t) Notify did not wake quiet event loop\n")));
80 this->result_ = -1;
82 else
84 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Notify woke quiet event loop\n")));
86 return 0;
89 static int
90 run_quiet_notify_test ()
92 ACE_DEBUG ((LM_DEBUG, "(%t) Starting quiet notify test\n"));
93 Quiet_Notify_Tester t;
94 if (t.open () == -1)
95 ACE_ERROR_RETURN ((LM_ERROR,
96 ACE_TEXT ("%p\n"),
97 ACE_TEXT ("Quiet notify activate")),
98 -1);
99 // Now sleep a bit, then do a simple, reactor wake-up
100 ACE_OS::sleep (SHORT_TIMEOUT);
101 t.reactor ()->notify ();
102 t.wait ();
103 ACE_DEBUG ((LM_DEBUG, "(%t) Quiet notify test done\n"));
104 return t.result ();
108 class Supplier_Task : public ACE_Task<ACE_MT_SYNCH>
110 public:
111 /// Constructor.
112 Supplier_Task (int disable_notify_pipe,
113 const ACE_Time_Value &tv);
115 /// Destructor.
116 ~Supplier_Task () override;
118 //FUZZ: disable check_for_lack_ACE_OS
119 /// Make this an Active Object.
120 int open (void * = 0) override;
122 /// Close down the supplier.
123 ///FUZZ: enable check_for_lack_ACE_OS
124 int close (u_long) override;
126 /// Generates events and sends them to the <Reactor>'s <notify>
127 /// method.
128 int svc () override;
130 /// Releases the <waiter_> semaphore when called by the <Reactor>'s
131 /// notify handler.
132 int handle_exception (ACE_HANDLE) override;
135 * Called every time through the main <ACE_Reactor> event loop to
136 * illustrate the difference between "limited" and "unlimited"
137 * notification.
139 int handle_output (ACE_HANDLE) override;
141 /// Release the <waiter_>.
142 void release ();
144 private:
145 /// Perform the notifications.
146 int perform_notifications (int notifications);
148 /// Used to hand-shake between the <Supplier_Task> and the
149 /// <Reactor>'s notify mechanism.
150 ACE_Thread_Semaphore waiter_;
153 * We use this pipe just to get a handle that is always "active,"
154 * i.e., the <ACE_Reactor> will always dispatch its <handle_output>
155 * method.
157 ACE_Pipe pipe_;
159 /// Keeps track of whether the notification pipe in the <ACE_Reactor>
160 /// has been diabled or not.
161 int disable_notify_pipe_;
164 * Keeps track of whether we're running with a <LONG_TIMEOUT>, which
165 * is used for the ACE_HAS_REACTOR_NOTIFICATION_QUEUE portion of
166 * this test.
168 int long_timeout_;
171 void
172 Supplier_Task::release ()
174 this->waiter_.release ();
177 Supplier_Task::Supplier_Task (int disable_notify_pipe,
178 const ACE_Time_Value &tv)
179 : waiter_ ((unsigned int) 0), // Make semaphore "locked" by default.
180 disable_notify_pipe_ (disable_notify_pipe),
181 long_timeout_ (tv.sec () == LONG_TIMEOUT)
186 Supplier_Task::open (void *)
188 // Create the pipe.
189 int result;
191 result = this->pipe_.open ();
192 ACE_TEST_ASSERT (result != -1);
194 // Register the pipe's write handle with the <Reactor> for writing.
195 // This should mean that it's always "active."
196 if (long_timeout_ == 0)
198 result = ACE_Reactor::instance ()->register_handler
199 (this->pipe_.write_handle (),
200 this,
201 ACE_Event_Handler::WRITE_MASK);
202 ACE_TEST_ASSERT (result != -1);
205 // Make this an Active Object.
206 result = this->activate (THR_BOUND | THR_DETACHED);
207 ACE_TEST_ASSERT (result != -1);
208 return 0;
212 Supplier_Task::close (u_long)
214 ACE_DEBUG ((LM_DEBUG,
215 ACE_TEXT ("(%t) Supplier_Task::close\n")));
217 int result;
219 if (long_timeout_ == 0)
221 result = ACE_Reactor::instance ()->remove_handler
222 (this->pipe_.write_handle (),
223 ACE_Event_Handler::WRITE_MASK);
224 ACE_TEST_ASSERT (result != -1);
226 else
228 // Wait to be told to shutdown by the main thread.
230 ACE_DEBUG ((LM_DEBUG,
231 ACE_TEXT ("(%t) waiting to be shutdown by main thread\n")));
232 result = this->waiter_.acquire ();
233 ACE_TEST_ASSERT (result != -1);
235 return 0;
238 Supplier_Task::~Supplier_Task ()
240 ACE_DEBUG ((LM_DEBUG,
241 ACE_TEXT ("(%t) ~Supplier_Task\n")));
242 this->pipe_.close ();
246 Supplier_Task::perform_notifications (int notifications)
248 ACE_Reactor::instance ()->max_notify_iterations (notifications);
250 size_t iterations = ACE_MAX_ITERATIONS;
252 if (this->long_timeout_)
254 iterations *= (iterations * iterations * 2);
255 #if defined (ACE_VXWORKS)
256 // scale down otherwise the test won't finish in time
257 iterations /= 4;
258 #endif
261 for (size_t i = 0; i < iterations; i++)
263 ACE_DEBUG ((LM_DEBUG,
264 ACE_TEXT ("(%t) notifying reactor on iteration %d\n"),
265 i));
267 int result;
269 // Notify the Reactor, which will call <handle_exception>.
270 result = ACE_Reactor::instance ()->notify (this);
271 if (result == -1)
273 if (errno == ETIME)
274 ACE_DEBUG ((LM_DEBUG,
275 ACE_TEXT ("(%t) %p\n"),
276 ACE_TEXT ("notify")));
277 else
278 ACE_TEST_ASSERT (result != -1);
281 // Wait for our <handle_exception> method to release the
282 // semaphore.
283 if (this->long_timeout_ == 0
284 && this->disable_notify_pipe_ == 0)
286 result = this->waiter_.acquire ();
287 ACE_TEST_ASSERT (result != -1);
291 return 0;
295 Supplier_Task::svc ()
297 ACE_DEBUG ((LM_DEBUG,
298 ACE_TEXT ("(%t) **** starting unlimited notifications test\n")));
300 // Allow an unlimited number of iterations per
301 // <ACE_Reactor::notify>.
302 this->perform_notifications (-1);
304 if (this->long_timeout_ == 0)
306 ACE_DEBUG ((LM_DEBUG,
307 ACE_TEXT ("(%t) **** starting limited notifications test\n")));
309 // Only allow 1 iteration per <ACE_Reactor::notify>
310 this->perform_notifications (1);
312 ACE_DEBUG ((LM_DEBUG,
313 ACE_TEXT ("(%t) **** exiting thread test\n")));
315 return 0;
319 Supplier_Task::handle_exception (ACE_HANDLE handle)
321 ACE_TEST_ASSERT (handle == ACE_INVALID_HANDLE);
322 ACE_DEBUG ((LM_DEBUG,
323 ACE_TEXT ("(%t) handle_exception\n")));
325 this->waiter_.release ();
326 return 0;
330 Supplier_Task::handle_output (ACE_HANDLE handle)
332 ACE_TEST_ASSERT (handle == this->pipe_.write_handle ());
333 ACE_DEBUG ((LM_DEBUG,
334 ACE_TEXT ("(%t) handle_output\n")));
336 // This function is called by the main thread, believe it or not :-)
337 // That's because the pipe's write handle is always active. Thus,
338 // we can give the <Supplier_Task> a chance to run in its own
339 // thread.
340 ACE_OS::thr_yield ();
342 return 0;
345 static int
346 run_test (int disable_notify_pipe,
347 const ACE_Time_Value &tv)
349 // Create special reactors with the appropriate flags enabled.
351 ACE_Select_Reactor *reactor_impl = 0;
352 if (disable_notify_pipe)
353 ACE_NEW_RETURN (reactor_impl,
354 ACE_Select_Reactor (0, 0, 1),
355 -1);
356 else
357 ACE_NEW_RETURN (reactor_impl,
358 ACE_Select_Reactor,
359 -1);
361 ACE_Reactor *reactor;
362 ACE_NEW_RETURN (reactor,
363 ACE_Reactor (reactor_impl, 1), // Delete implementation
364 -1);
366 // Make sure this stuff gets cleaned up when this function exits.
367 std::unique_ptr<ACE_Reactor> r (reactor);
369 // Set the Singleton Reactor.
370 ACE_Reactor *orig_reactor = ACE_Reactor::instance (reactor);
371 ACE_TEST_ASSERT (ACE_LOG_MSG->op_status () != -1);
372 ACE_TEST_ASSERT (ACE_Reactor::instance () == reactor);
374 Supplier_Task task (disable_notify_pipe,
375 tv);
376 ACE_TEST_ASSERT (ACE_LOG_MSG->op_status () != -1);
378 int result;
380 result = task.open ();
381 ACE_TEST_ASSERT (result != -1);
383 if (tv.sec () == LONG_TIMEOUT)
384 // Sleep for a while so that the <ACE_Reactor>'s notification
385 // buffers will fill up!
386 ACE_OS::sleep (tv);
388 int shutdown = 0;
390 // Run the event loop that handles the <handle_output> and
391 // <handle_exception> notifications.
392 for (int iteration = 1;
393 shutdown == 0;
394 iteration++)
396 ACE_Time_Value timeout (tv);
398 ACE_DEBUG ((LM_DEBUG,
399 ACE_TEXT ("(%t) starting handle_events() on iteration %d")
400 ACE_TEXT (" with time-out = %d seconds\n"),
401 iteration,
402 timeout.sec ()));
404 // Use a timeout to inform the Reactor when to shutdown.
405 switch (ACE_Reactor::instance ()->handle_events (timeout))
407 case -1:
408 if (! disable_notify_pipe)
409 ACE_ERROR ((LM_ERROR,
410 ACE_TEXT ("(%t) %p\n"),
411 ACE_TEXT ("reactor")));
412 shutdown = 1;
413 break;
414 /* NOTREACHED */
415 case 0:
416 ACE_DEBUG ((LM_DEBUG,
417 ACE_TEXT ("(%t) handle_events timed out\n")));
418 shutdown = 1;
419 break;
420 /* NOTREACHED */
421 default:
422 break;
423 /* NOTREACHED */
427 if (tv.sec () == LONG_TIMEOUT)
429 ACE_DEBUG ((LM_DEBUG,
430 ACE_TEXT ("(%t) releasing supplier task thread\n")));
431 task.release ();
433 ACE_Reactor::instance (orig_reactor);
434 return 0;
437 #endif /* ACE_HAS_THREADS */
440 * @class Purged_Notify
442 * @brief <run_notify_purge_test> tests the reactor's
443 * purge_pending_notifications function. It does 2 notifications,
444 * and explicitly cancels one, and deletes the other's event
445 * handler, which should cause it to be cancelled as well.
447 class Purged_Notify : public ACE_Event_Handler
449 int handle_exception (ACE_HANDLE = ACE_INVALID_HANDLE) override
451 ACE_ERROR_RETURN ((LM_ERROR,
452 ACE_TEXT ("Got a notify that should have been purged!\n")),
457 static int
458 run_notify_purge_test ()
460 int status;
461 ACE_Reactor *r = ACE_Reactor::instance ();
463 Purged_Notify n1;
464 Purged_Notify *n2;
466 ACE_NEW_RETURN (n2, Purged_Notify, -1);
467 std::unique_ptr<Purged_Notify> ap (n2);
469 // First test:
470 // Notify EXCEPT, and purge ALL
471 r->notify (&n1); // the mask is EXCEPT_MASK
473 status = r->purge_pending_notifications (&n1);
474 if (status == -1 && errno == ENOTSUP)
475 return 0; // Select Reactor w/o ACE_HAS_REACTOR_NOTIFICATION_QUEUE
476 if (status != 1)
477 ACE_ERROR ((LM_ERROR,
478 ACE_TEXT ("Purged %d notifies; expected 1\n"),
479 status));
480 // Second test:
481 // Notify READ twice, and WRITE once, and purge READ and WRITE - should purge 3 times.
482 r->notify (&n1, ACE_Event_Handler::READ_MASK);
483 r->notify (&n1, ACE_Event_Handler::READ_MASK);
484 r->notify (&n1, ACE_Event_Handler::WRITE_MASK);
485 status = r->purge_pending_notifications
486 (&n1, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK);
487 if (status != 3)
488 ACE_ERROR ((LM_ERROR,
489 ACE_TEXT ("Purged %d notifies; expected 3\n"),
490 status));
491 // Third test:
492 // Notify READ on 2 handlers, and purge READ|WRITE on all handlers. Should purge 2
493 r->notify (&n1, ACE_Event_Handler::READ_MASK);
494 r->notify (n2, ACE_Event_Handler::READ_MASK);
495 status = r->purge_pending_notifications
496 (0, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK);
497 if (status != 2)
498 ACE_ERROR ((LM_ERROR,
499 ACE_TEXT ("Purged %d notifies; expected 2\n"),
500 status));
501 // Forth test:
502 // Notify EXCEPT and WRITE, purge READ. Should not purge
503 r->notify (&n1); // the mask is EXCEPT_MASK
504 r->notify (&n1, ACE_Event_Handler::WRITE_MASK);
505 status = r->purge_pending_notifications
506 (&n1, ACE_Event_Handler::READ_MASK);
507 if (status != 0)
508 ACE_ERROR ((LM_ERROR,
509 ACE_TEXT ("Purged %d notifies; expected 0\n"),
510 status));
511 // Fifth test:
512 r->notify (n2);
514 // The destructor of the event handler no longer removes the
515 // notifications. It is the application's responsability to do
516 // so.
517 r->purge_pending_notifications(n2,
518 ACE_Event_Handler::ALL_EVENTS_MASK);
519 r->purge_pending_notifications(&n1,
520 ACE_Event_Handler::ALL_EVENTS_MASK);
523 ACE_Time_Value t (1);
524 status = r->handle_events (t); // Should be nothing to do, and time out
525 return status < 0 ? 1 : 0; // Return 0 for all ok, else error
530 run_main (int, ACE_TCHAR *[])
532 ACE_START_TEST (ACE_TEXT ("Reactor_Notify_Test"));
534 int test_result = 0; // Innocent until proven guilty
536 if (0 == run_notify_purge_test ())
538 ACE_DEBUG ((LM_DEBUG,
539 ACE_TEXT ("purge_pending_notifications test OK\n")));
541 else
543 ACE_ERROR ((LM_ERROR,
544 ACE_TEXT ("purge_pending_notifications test FAIL\n")));
545 test_result = 1;
548 #if defined (ACE_HAS_THREADS)
549 if (0 != run_quiet_notify_test ())
550 test_result = 1;
552 ACE_Time_Value timeout (SHORT_TIMEOUT);
554 ACE_DEBUG ((LM_DEBUG,
555 ACE_TEXT ("(%t) running tests with notify pipe enabled")
556 ACE_TEXT (" and time-out = %d seconds\n"),
557 timeout.sec ()));
558 run_test (0, timeout);
560 ACE_DEBUG ((LM_DEBUG,
561 ACE_TEXT ("(%t) running tests with notify pipe disabled")
562 ACE_TEXT (" and time-out = %d seconds\n"),
563 timeout.sec ()));
564 run_test (1, timeout);
566 timeout.set (LONG_TIMEOUT, 0);
567 ACE_DEBUG ((LM_DEBUG,
568 ACE_TEXT ("(%t) running tests with reactor notification ")
569 ACE_TEXT ("pipe enabled\n")
570 ACE_TEXT (" and time-out = %d seconds\n"),
571 timeout.sec ()));
572 run_test (0, timeout);
574 #else
575 ACE_ERROR ((LM_INFO,
576 ACE_TEXT ("threads not supported on this platform\n")));
577 #endif /* ACE_HAS_THREADS */
578 ACE_END_TEST;
579 return test_result;