static bool timeout_test (void) { bool status = true; SYNCH_QUEUE mq; MyTask task1; task1.create_reactor (); task1.start (1); TestHandler test_handler (task1.get_reactor (), mq); // The reactor of taks1 that uses a hrtimer will trigger a timeout in // 5 seconds which will enqueue a message block in the queue. At the // same moment we calculate a timeout for the dequeue operation for // 3 seconds in the future. Than we set the system time 4 seconds back. // The condition should timeout because the queue is empty and the trigger // only fires after the condition has timed out. // Next we start another dequeue for 3 seconds in the future which should // return before timing out because by then the trigger should have fired. // In case of using regular system time policy for message queue and // dequeue timeouts the first dequeue would not have timed out because // between calculating the timeout and starting the dequeue the system time // shifted back 4 sec causing the trigger to fire before the timeout elapsed. // In case timeshifting does not work because of priority problems or such // the test should succeed. if (!test_handler.trigger_in (ACE_Time_Value (5, 0))) ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) Unable to schedule trigger.\n"), false); if (!mq.is_empty ()) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("New queue is not empty!\n"))); status = false; } else { ACE_Message_Block *b = 0; ACE_Time_Value_T<ACE_Monotonic_Time_Policy> tv; tv = (tv.now () + ACE_Time_Value (3,0)); // Now (monotonic time) + 3 sec // shift back in time 4 sec set_system_time (ACE_OS::gettimeofday () - ACE_Time_Value (4, 0)); if (mq.dequeue_head (b, &tv) != -1) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("Dequeued before timeout elapsed!\n"))); status = false; } else if (errno != EWOULDBLOCK) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("Dequeue timeout should be EWOULDBLOCK, got"))); status = false; } else { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("First dequeue timed out: OK\n"))); tv = (tv.now () + ACE_Time_Value (3,0)); // Now (monotonic time) + 3 sec if (mq.dequeue_head (b, &tv) != -1) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Second dequeue succeeded: OK\n"))); delete b; } else { ACE_ERROR ((LM_ERROR, ACE_TEXT ("Second dequeue timed out!\n"))); status = false; } } // restore time set_system_time (ACE_OS::gettimeofday () + ACE_Time_Value (4, 0)); } ACE_DEBUG((LM_INFO, "(%P|%t) Asking worker thread to finish.\n")); task1.stop (); ACE_Thread_Manager::instance ()->wait (); return status; }
int MyTask::svc (void) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%P|%t) MyTask::svc started\n"))); // Now (according to task time policy = monotonic time) ACE_Time_Value_T<ACE_Monotonic_Time_Policy> tv (this->gettimeofday ()); { ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1); ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%P|%t) MyTask::svc - signalling waiter\n"))); this->cond_.signal (); // signal waiter we have started // waiter will shift system time back 4 sec after this which would mess // up the first wait for a message if we were not using monotonic time } if (!this->msg_queue ()->is_empty ()) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("New task queue is not empty!\n"))); this->status_ = -1; } else { ACE_Message_Block *b; tv += ACE_Time_Value (3,0); // Now + 3 sec if (this->getq (b, &tv) != -1) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("Dequeued before timeout elapsed!\n"))); this->status_ = -1; } else if (errno != EWOULDBLOCK) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("Dequeue timeout should be EWOULDBLOCK, got"))); this->status_ = -1; } else { ACE_Time_Value_T<ACE_Monotonic_Time_Policy> tv_now (this->gettimeofday ()); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("First getq timed out at %#T (timeout was %#T)\n"), &tv_now, &tv)); tv = this->gettimeofday () + ACE_Time_Value (4,0); // Now (monotonic time) + 3 sec if (this->getq (b, &tv) != -1) { tv_now = tv.now (); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Second getq succeeded at %#T\n"), &tv_now)); delete b; } else { ACE_ERROR ((LM_ERROR, ACE_TEXT ("Second getq timed out!\n"))); this->status_ = -1; } } } { ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1); ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%P|%t) MyTask::svc - waiting for stop\n"))); if (!this->stop_) this->cond_.wait (); } ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) MyTask finished\n"))); return 0; }