diff options
Diffstat (limited to 'ACE/ace/QtReactor.cpp')
-rw-r--r-- | ACE/ace/QtReactor.cpp | 629 |
1 files changed, 629 insertions, 0 deletions
diff --git a/ACE/ace/QtReactor.cpp b/ACE/ace/QtReactor.cpp new file mode 100644 index 00000000000..a6983ab9463 --- /dev/null +++ b/ACE/ace/QtReactor.cpp @@ -0,0 +1,629 @@ +//$Id$ + +#include "ace/QtReactor.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE (ACE_QtReactor) + +// Must be called with lock held + +ACE_QtReactor::ACE_QtReactor (QApplication *qapp , + ACE_Sig_Handler *sh, + ACE_Timer_Queue *tq, + int disable_notify_pipe, + ACE_Reactor_Notify *notify, + int mask_signals, + int s_queue ): + ACE_Select_Reactor( sh, tq, disable_notify_pipe, + notify, mask_signals, s_queue), + qapp_(qapp), + qtime_ (0) +{ + reopen_notification_pipe(); +} + +// Must be called with lock held +ACE_QtReactor::ACE_QtReactor (size_t size, + QApplication *qapp, + int restart, + ACE_Sig_Handler *sh, + ACE_Timer_Queue *tq, + int disable_notify_pipe, + ACE_Reactor_Notify *notify, + int mask_signals, + int s_queue): + ACE_Select_Reactor( size, restart, sh, tq, + disable_notify_pipe, notify, mask_signals, + s_queue ), + qapp_(qapp), + qtime_ (0) + +{ + reopen_notification_pipe(); +} + +void ACE_QtReactor::reopen_notification_pipe( void) +{ + // When the ACE_Select_Reactor is constructed it creates the notify + // pipe and registers it with the register_handler_i() method. The + // QtReactor overloads this method BUT because the + // register_handler_i occurs when constructing the base class + // ACE_Select_Reactor, the ACE_Select_Reactor register_handler_i() + // is called not the QtReactor register_handler_i(). This means + // that the notify pipe is registered with the ACE_Select_Reactor + // event handling code not the QtReactor and so notfications don't + // work. To get around this we simply close and re-opened the + // notification handler in the constructor of the QtReactor. + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + if ( initialized_ ) + { + this->notify_handler_->close (); + + // Patch for MS Windows: close and open doesn't clear the read + // fd_set, so reset it manually + this->wait_set_.rd_mask_.reset (); + + this->notify_handler_->open (this, 0); + } +#endif /* ACE_MT_SAFE */ +} + +ACE_QtReactor::~ACE_QtReactor (void) +{ + // iterate over QSocketNotifiers for read and release them + MAP::ITERATOR iter = this->read_notifier_.begin (); + MAP::ITERATOR iterEnd = this->read_notifier_.end (); + while( iter != iterEnd ) + { + MAP::ENTRY &entry = *iter; + // QOBject destructor notifies qapplication (hopefully) on delete + delete entry.int_id_; + ++iter; + } + + // iterate over QSocketNotifiers for write and release them + this->write_notifier_.begin (); + this->write_notifier_.end (); + while( iter != iterEnd ) + { + MAP::ENTRY &entry = *iter; + // QOBject destructor notifies qapplication (hopefully) on delete + delete entry.int_id_; + ++iter; + } + + // iterate over QSocketNotifiers for exceptions and release them + this->exception_notifier_.begin (); + this->exception_notifier_.end (); + while( iter != iterEnd ) + { + MAP::ENTRY &entry = *iter; + // QOBject destructor notifies qapplication (hopefully) on delete + delete entry.int_id_; + ++iter; + } + + // QOBject destructor notifies qapplication (hopefully) on delete + delete qtime_; +} + +void +ACE_QtReactor::qapplication (QApplication *qapp) +{ + // reparent QSocketNotifiers and QTimer + qapp_ = qapp ; +} + +void +ACE_QtReactor::timeout_event (void) +{ + // Deal with any timer events + ACE_Select_Reactor_Handle_Set handle_set; + this->dispatch (0, handle_set ); + + // Set next timeout signal + this->reset_timeout (); +} + +void +ACE_QtReactor::read_event (int p_handle) +{ + ACE_TRACE ("ACE_QtReactor::read_event"); + + ACE_HANDLE handle = ACE_HANDLE( p_handle ); + +#ifdef ACE_QTREACTOR_CLEAR_PENDING_EVENTS + // disable socket notifier to clear pending events + QSocketNotifier *qsock_notifier = 0; + if ( ( this->read_notifier_.find( handle, + qsock_notifier) != -1) ) + qsock_notifier->setEnabled( false ); +#endif /* ACE_QTREACTOR_CLEAR_PENDING_EVENTS */ + + // The core of read event handling + ACE_Select_Reactor_Handle_Set dispatch_set; + + dispatch_set.rd_mask_.set_bit ( handle ); + this->dispatch (1, dispatch_set); + +#ifdef ACE_QTREACTOR_CLEAR_PENDING_EVENTS + // enable socket notifier according to current mask + ACE_Reactor_Mask mask = 0; + mask = mask_ops( handle, mask, ACE_Reactor::GET_MASK ); + if ( -1 != mask ) + set_enable_flag_by_mask ( 1, handle, mask); +#endif /* ACE_QTREACTOR_CLEAR_PENDING_EVENTS */ +} + +void +ACE_QtReactor::write_event (int p_handle) +{ + ACE_TRACE ("ACE_QtReactor::write_event"); + + ACE_HANDLE handle = ACE_HANDLE( p_handle ); + +#ifdef ACE_QTREACTOR_CLEAR_PENDING_EVENTS + // disable socket notifier to clear pending events + QSocketNotifier *qsock_notifier = 0; + if ( ( this->write_notifier_.find( handle, qsock_notifier) != -1) ) + qsock_notifier->setEnabled( false ); +#endif /* ACE_QTREACTOR_CLEAR_PENDING_EVENTS */ + + // The core of write event handling + ACE_Select_Reactor_Handle_Set dispatch_set; + + dispatch_set.wr_mask_.set_bit( handle ); + this->dispatch (1, dispatch_set); + +#ifdef ACE_QTREACTOR_CLEAR_PENDING_EVENTS + // enable socket notifier according to current mask + ACE_Reactor_Mask mask = 0; + mask = mask_ops( handle, mask, ACE_Reactor::GET_MASK ); + if ( -1 != mask ) + set_enable_flag_by_mask ( 1, handle, mask); +#endif /* ACE_QTREACTOR_CLEAR_PENDING_EVENTS */ +} + +void +ACE_QtReactor::exception_event (int p_handle) +{ + ACE_TRACE ("ACE_QtReactor::exception_event"); + + ACE_HANDLE handle = ACE_HANDLE( p_handle ); + + +#ifdef ACE_QTREACTOR_CLEAR_PENDING_EVENTS + // disable socket notifier to clear pending events + QSocketNotifier *qsock_notifier = 0; + if ( ( this->exception_notifier_.find( handle, qsock_notifier) != -1) ) + qsock_notifier->setEnabled( false ); +#endif /* ACE_QTREACTOR_CLEAR_PENDING_EVENTS */ + + // The core of exception event handling + ACE_Select_Reactor_Handle_Set dispatch_set; + + dispatch_set.ex_mask_.set_bit( handle ); + dispatch (1, dispatch_set); + +#ifdef ACE_QTREACTOR_CLEAR_PENDING_EVENTS + // enable socket notifier according to current mask + ACE_Reactor_Mask mask = 0; + mask = mask_ops( handle, mask, ACE_Reactor::GET_MASK ); + if ( -1 != mask ) + set_enable_flag_by_mask ( 1, handle, mask); +#endif /* ACE_QTREACTOR_CLEAR_PENDING_EVENTS */ +} + +int +ACE_QtReactor::set_enable_flag_by_mask (int flag_value, + ACE_HANDLE handle, + ACE_Reactor_Mask mask) +{ + QSocketNotifier *qs_not; + + if (ACE_BIT_ENABLED(mask, ACE_Event_Handler::READ_MASK) || + ACE_BIT_ENABLED( mask, ACE_Event_Handler::ACCEPT_MASK)) + { + // Find the current notifier + qs_not = 0; + if ((this->read_notifier_.find (handle, qs_not) == -1)) + return -1; + + qs_not->setEnabled (flag_value); + } + + if (ACE_BIT_ENABLED( mask, ACE_Event_Handler::WRITE_MASK) || + ACE_BIT_ENABLED( mask, ACE_Event_Handler::ACCEPT_MASK) || + ACE_BIT_ENABLED( mask, ACE_Event_Handler::CONNECT_MASK)) + { + qs_not = 0; + if ((this->write_notifier_.find (handle, qs_not) == -1)) + return -1; + + qs_not->setEnabled (flag_value); + } + + if (ACE_BIT_ENABLED( mask, + ACE_Event_Handler::EXCEPT_MASK)) + { + qs_not = 0; + if ((this->exception_notifier_.find (handle, qs_not) == -1)) + return -1; + + qs_not->setEnabled (flag_value); + } + + return 0; +} + +int +ACE_QtReactor::bit_ops (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + ACE_Select_Reactor_Handle_Set &handle_set, + int ops) +{ + int result; + ACE_Select_Reactor_Handle_Set preserved_handle_set = handle_set; + + // Call regular bit_ops + if ((result = ACE_Select_Reactor::bit_ops (handle, mask, handle_set, ops)) == -1) + return -1; + + // disable or enable the notifiers based on handle_set and mask + int enableFlag = -1; + if (&handle_set == &this->suspend_set_) + enableFlag = 0; + else if (&handle_set == &this->wait_set_) + enableFlag = 1; + else + // We have no work to do here, so just return + return result; + + switch (ops) + { + case ACE_Reactor::SET_MASK: + case ACE_Reactor::ADD_MASK: + // Enable or disable notifiers based on the specified masks + if (this->set_enable_flag_by_mask (enableFlag, handle, mask) == -1) + { + // We can't just return -1 here because we'll have half-changed things. + // So, we need to restore the old handle_set, then return -1. + handle_set = preserved_handle_set; + return -1; + } + break; + + case ACE_Reactor::CLR_MASK: + if (this->set_enable_flag_by_mask (!enableFlag, handle, mask) == -1) + { + handle_set = preserved_handle_set; + return -1; + } + break; + + default: + // we take no action for any other operations + break; + } + + return result; +} + +void +ACE_QtReactor::create_notifiers_for_handle (ACE_HANDLE handle) +{ + QSocketNotifier *qsock_notifier = 0; + + // if there is already a read socket notifier for this handle, do nothing + // otherwise create read notifier + if ( ( this->read_notifier_.find (handle, + qsock_notifier) == -1) ) + { + ACE_NEW (qsock_notifier, + QSocketNotifier (int(handle), QSocketNotifier::Read, this)); + this->read_notifier_.bind (handle, + qsock_notifier); + QObject::connect (qsock_notifier, + SIGNAL (activated (int)), + this, + SLOT (read_event (int))) ; + // disable; it will be enabled by the regular register_handler_i if + // necessary + qsock_notifier->setEnabled (0); + } + + qsock_notifier = 0; + + + // if there is already a write socket notifier for this handle, do nothing + // otherwise create read notifier + if ((this->write_notifier_.find (handle, + qsock_notifier) == -1)) + { + ACE_NEW (qsock_notifier, + QSocketNotifier (int(handle), QSocketNotifier::Write, this)); + + this->write_notifier_.bind (handle, + qsock_notifier); + + QObject::connect (qsock_notifier, + SIGNAL (activated (int)), + this, + SLOT (write_event (int))); + // disable; it will be enabled by the regular register_handler_i if + // necessary + qsock_notifier->setEnabled (0); + } + + + qsock_notifier = 0; + + // if there is already a write socket notifier for this handle, do nothing + // otherwise create read notifier + if ((this->exception_notifier_.find (handle, + qsock_notifier) == -1)) + { + + ACE_NEW (qsock_notifier, + QSocketNotifier (int(handle), QSocketNotifier::Exception, this)); + + this->exception_notifier_.bind (handle, + qsock_notifier); + + QObject::connect (qsock_notifier, + SIGNAL (activated (int)), + this, + SLOT (exception_event (int))) ; + // disable; it will be enabled by the regular register_handler_i if + // necessary + qsock_notifier->setEnabled (0); + } +} + +void +ACE_QtReactor::destroy_notifiers_for_handle (ACE_HANDLE handle) +{ + QSocketNotifier *qsock_notifier = 0; + + // Looks for the handle in the maps and removes them. + + if ((this->read_notifier_.find (handle, + qsock_notifier) != -1)) + { + this->read_notifier_.unbind (handle, + qsock_notifier); + delete qsock_notifier; + } + + if ((this->write_notifier_.find (handle, + qsock_notifier) != -1)) + { + this->write_notifier_.unbind (handle, + qsock_notifier); + delete qsock_notifier; + } + + + if ((this->exception_notifier_.find (handle, + qsock_notifier) != -1)) + { + this->exception_notifier_.unbind (handle, + qsock_notifier); + delete qsock_notifier; + } +} + +int +ACE_QtReactor::register_handler_i (ACE_HANDLE handle , + ACE_Event_Handler *handler, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_QtReactor::register_handler_i"); + + this->create_notifiers_for_handle (handle); + + int result; + if ((result = ACE_Select_Reactor::register_handler_i(handle, + handler, + mask )) + == -1) + { + // destroy notifiers only when there is no handler for handle + if ( !ACE_Select_Reactor::find_handler( handle ) ) + this->destroy_notifiers_for_handle (handle); + return -1; + } + + return 0; +} + +int +ACE_QtReactor::register_handler_i (const ACE_Handle_Set &handles, + ACE_Event_Handler *handler, + ACE_Reactor_Mask mask) +{ + return ACE_Select_Reactor::register_handler_i(handles, + handler, + mask); +} + +int ACE_QtReactor::remove_handler_i (ACE_HANDLE handle , + ACE_Reactor_Mask mask ) +{ + ACE_TRACE ("ACE_QtReactor::remove_handler_i"); + + int result = ACE_Select_Reactor::remove_handler_i (handle, mask); + // destroy notifiers only when there is no handler for handle + if ( !ACE_Select_Reactor::find_handler( handle ) ) + this->destroy_notifiers_for_handle (handle); + return result; +} + + +int +ACE_QtReactor::remove_handler_i (const ACE_Handle_Set &handles, + ACE_Reactor_Mask mask) +{ + return ACE_Select_Reactor::remove_handler_i (handles, + mask); +} + +// The following functions ensure that there is an Qt timeout for the +// first timeout in the Reactor's Timer_Queue. + +void +ACE_QtReactor::reset_timeout (void) +{ + if (this->qtime_ != 0) + { + delete this->qtime_; + this->qtime_ = 0; + } + + ACE_Time_Value *max_wait_time = + this->timer_queue_->calculate_timeout (0) ; + + if (max_wait_time) + { + ACE_NEW (this->qtime_, + QTimer); + + QObject::connect (qtime_, + SIGNAL (timeout ()), + this, + SLOT (timeout_event ())); + + qtime_->start(max_wait_time->msec(), 1); + } + +} + + +long +ACE_QtReactor::schedule_timer (ACE_Event_Handler *handler, + const void *arg, + const ACE_Time_Value &delay_time, + const ACE_Time_Value &interval) +{ + ACE_TRACE ("ACE_QtReactor::schedule_timer"); + ACE_MT (ACE_GUARD_RETURN (ACE_Select_Reactor_Token, + ace_mon, + this->token_, + -1)); + + long result; + if ((result = ACE_Select_Reactor::schedule_timer(handler, + arg, + delay_time, + interval)) == -1 ) + return -1; + else + { + this->reset_timeout (); + return result; + } +} + +int +ACE_QtReactor::cancel_timer (ACE_Event_Handler *handler, + int dont_call_handle_close) +{ + ACE_TRACE ("ACE_QtReactor::cancel_timer"); + + if (ACE_Select_Reactor::cancel_timer (handler, + dont_call_handle_close ) == -1 ) + return -1 ; + else + { + this->reset_timeout( ) ; + return 0 ; + } +} + +int ACE_QtReactor::cancel_timer (long timer_id, + const void **arg, + int dont_call_handle_close ) +{ + ACE_TRACE ("ACE_QtReactor::cancel_timer") ; + + if (ACE_Select_Reactor::cancel_timer (timer_id, + arg, + dont_call_handle_close ) == -1 ) + return -1 ; + else + { + this->reset_timeout( ) ; + return 0 ; + } +} + +// mbrudka: who needs QtWaitForMultipleEvents? It seems it's cargo load now! +int +ACE_QtReactor::QtWaitForMultipleEvents (int width, + ACE_Select_Reactor_Handle_Set &wait_set, + ACE_Time_Value * /*max_wait_time*/) +{ + // Check to make sure our handle's are all usable. + ACE_Select_Reactor_Handle_Set temp_set = wait_set; + + if (ACE_OS::select (width, + temp_set.rd_mask_, + temp_set.wr_mask_, + temp_set.ex_mask_, + (ACE_Time_Value *) &ACE_Time_Value::zero ) == -1) + return -1; // Bad file arguments... + + // Qt processing. + this->qapp_->processOneEvent (); + + // Reset the width, in case it changed during the upcalls. + width = handler_rep_.max_handlep1 (); + + // Now actually read the result needed by the <Select_Reactor> using + // <select>. + return ACE_OS::select(width, + wait_set.rd_mask_, + wait_set.wr_mask_, + wait_set.ex_mask_, + (ACE_Time_Value *) &ACE_Time_Value::zero); +} + +// mbrudka: who needs wait_for_multiple_events? It seems it's cargo load now! +int +ACE_QtReactor::wait_for_multiple_events ( + ACE_Select_Reactor_Handle_Set &handle_set, + ACE_Time_Value *max_wait_time) +{ + ACE_TRACE ("ACE_QtReactor::wait_for_multiple_events"); + + int nfound = 0; + do + { + max_wait_time = this->timer_queue_->calculate_timeout (max_wait_time); + size_t width = this->handler_rep_.max_handlep1 (); + handle_set.rd_mask_ = this->wait_set_.rd_mask_; + handle_set.wr_mask_ = this->wait_set_.wr_mask_; + handle_set.ex_mask_ = this->wait_set_.ex_mask_; + + nfound = QtWaitForMultipleEvents (width, + handle_set, + max_wait_time); + + } while( nfound == -1 && this->handle_error () > 0 ); + + if (nfound > 0) + { +#if !defined (ACE_WIN32) + handle_set.rd_mask_.sync (this->handler_rep_.max_handlep1 ()); + handle_set.wr_mask_.sync (this->handler_rep_.max_handlep1 ()); + handle_set.ex_mask_.sync (this->handler_rep_.max_handlep1 ()); +#endif /* ACE_WIN32 */ + } + + return nfound; + // Timed out or input available +} + +ACE_END_VERSIONED_NAMESPACE_DECL |