简介
ACE_Reactor实现了reactor模式,其使用了桥接设计模式,实现类的抽象为ACE_Reactor_Impl
结构
主要包含下面几类接口
- 初始化
- open
- set_sig_handler
- timer_queue
- close
- 事件循环
- run_event_loop(静态方法)
- run_alertable_event_loop(静态方法)
- end_event_loop(静态方法)
- reset_event_loop(静态方法)
- run_reactor_event_loop
- run_alertable_reactor_event_loop
- end_reactor_event_loop
- handle_events
- alertable_handle_events
- 管理事件
- register_handler
- remove_handler
- suspend_handler
- resume_handler
- 定时器调度
- schedule_timer
- reset_timer_interval
- cancel_timer
- 通知
- notify
- max_notify_iterations
- purge_pending_notifications
ACE_Reactor_Impl 的实现类有以下几种
- ACE_Select_Reactor_Impl:ready_set_表示已经就绪的io句柄(不需要通过select),wait_set_表示调用select之前的io句柄集,dipatch_set_表示通过select后满足的io句柄,是在ACE_Select_Reactor_T中是如此,而在ACE_TP_Reactor是通过ready_set_
- ACE_Select_Reactor_T:要求在Reactor持有线程内运行,suspend_handler是将句柄从wait_set_和dipatch_set_清除,添加到suspend_set_中,resume_handler是将句柄从suspend_set_删除,添加到wait_set_中
- ACE_TP_Reactor:在没有事件时,会调用select得到事件句柄集,单个线程会处理一个事件,如果事件句柄集中还有没有处理的,则其它线程则直接从事件句柄集中分发
- ACE_QtReactor
- ACE_XtReactor
- ACE_FlReactor
- ACE_TkReactor
- ACE_Priority_Reactor
- ACE_Select_Reactor_T:要求在Reactor持有线程内运行,suspend_handler是将句柄从wait_set_和dipatch_set_清除,添加到suspend_set_中,resume_handler是将句柄从suspend_set_删除,添加到wait_set_中
- ACE_Dev_Poll_Reactor:suspend_handler是使用EPOLL_CTL_DEL将句柄从内核中删除,同时设置Event_Tuple的controlled标识为false,suspended标识为true,resume_handler则是与suspend_handler相反
- ACE_WFMO_Reactor
- ACE_Msg_WFMO_Reactor
通知唤醒ACE_Reactor是通过ACE_Reactor_Notify,不同的ACE_Reactor_Impl实现类有各自不同的通知实现类,主要包含如下
- ACE_Dev_Poll_Reactor_Notify
- ACE_Select_Reactor_Notify
- ACE_WFMO_Reactor_Notify
ACE_Reactor事件循环,以ACE_Dev_Poll_Reactor为例
什么时候handle_events返回小于0呢?
- reactor处理未激活状态时
- 中断时,信号处理没有处理
ACE_Reactor_Impl
抽象类
ACE_Select_Reactor_Impl
使用select作为io复用的reactor
owner_:创建ACE_Select_Reactor_Impl 的线程
ACE_Select_Reactor_T在handle_events_i时
template <class ACE_SELECT_REACTOR_TOKEN> int
ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::handle_events_i
(ACE_Time_Value *max_wait_time)
{
int result = -1;
ACE_SEH_TRY
{
// We use the data member dispatch_set_ as the current dispatch
// set.
// We need to start from a clean dispatch_set
this->dispatch_set_.rd_mask_.reset ();
this->dispatch_set_.wr_mask_.reset ();
this->dispatch_set_.ex_mask_.reset ();
int number_of_active_handles =
this->wait_for_multiple_events (this->dispatch_set_,
max_wait_time);
result =
this->dispatch (number_of_active_handles,
this->dispatch_set_);
}
ACE_SEH_EXCEPT (this->release_token ())
{
// As it stands now, we catch and then rethrow all Win32
// structured exceptions so that we can make sure to release the
// <token_> lock correctly.
}
return result;
}
template <class ACE_SELECT_REACTOR_TOKEN> int
ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::wait_for_multiple_events
(ACE_Select_Reactor_Handle_Set &dispatch_set,
ACE_Time_Value *max_wait_time)
{
ACE_TRACE ("ACE_Select_Reactor_T::wait_for_multiple_events");
ACE_Time_Value timer_buf (0);
ACE_Time_Value *this_timeout = 0;
int number_of_active_handles = this->any_ready (dispatch_set);
// If there are any bits enabled in the <ready_set_> then we'll
// handle those first, otherwise we'll block in <select>.
if (number_of_active_handles == 0)
{
do
{
if (this->timer_queue_ == 0)
return 0;
this_timeout =
this->timer_queue_->calculate_timeout (max_wait_time,
&timer_buf);
#ifdef ACE_WIN32
// This arg is ignored on Windows and causes pointer
// truncation warnings on 64-bit compiles.
int const width = 0;
#else
int const width = this->handler_rep_.max_handlep1 ();
#endif /* ACE_WIN32 */
dispatch_set.rd_mask_ = this->wait_set_.rd_mask_;
dispatch_set.wr_mask_ = this->wait_set_.wr_mask_;
dispatch_set.ex_mask_ = this->wait_set_.ex_mask_;
number_of_active_handles = ACE_OS::select (width,
dispatch_set.rd_mask_,
dispatch_set.wr_mask_,
dispatch_set.ex_mask_,
this_timeout);
}
while (number_of_active_handles == -1 && this->handle_error () > 0);
if (number_of_active_handles > 0)
{
#if !defined (ACE_WIN32)
// Resynchronize the fd_sets so their "max" is set properly.
dispatch_set.rd_mask_.sync (this->handler_rep_.max_handlep1 ());
dispatch_set.wr_mask_.sync (this->handler_rep_.max_handlep1 ());
dispatch_set.ex_mask_.sync (this->handler_rep_.max_handlep1 ());
#endif /* ACE_WIN32 */
}
else if (number_of_active_handles == -1)
{
// Normally, select() will reset the bits in dispatch_set
// so that only those filed descriptors that are ready will
// have bits set. However, when an error occurs, the bit
// set remains as it was when the select call was first made.
// Thus, we now have a dispatch_set that has every file
// descriptor that was originally waited for, which is not
// correct. We must clear all the bit sets because we
// have no idea if any of the file descriptors is ready.
//
// NOTE: We dont have a test case to reproduce this
// problem. But pleae dont ignore this and remove it off.
dispatch_set.rd_mask_.reset ();
dispatch_set.wr_mask_.reset ();
dispatch_set.ex_mask_.reset ();
}
}
// Return the number of events to dispatch.
return number_of_active_handles;
}
template <class ACE_SELECT_REACTOR_TOKEN> int
ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::any_ready
(ACE_Select_Reactor_Handle_Set &wait_set)
{
ACE_TRACE ("ACE_Select_Reactor_T::any_ready");
if (this->mask_signals_)
{
#if !defined (ACE_WIN32)
// Make this call signal safe.
ACE_Sig_Guard sb;
#endif /* ACE_WIN32 */
return this->any_ready_i (wait_set);
}
return this->any_ready_i (wait_set);
}
template <class ACE_SELECT_REACTOR_TOKEN> int
ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::any_ready_i
(ACE_Select_Reactor_Handle_Set &wait_set)
{
ACE_TRACE ("ACE_Select_Reactor_T::any_ready_i");
int const number_ready = this->ready_set_.rd_mask_.num_set ()
+ this->ready_set_.wr_mask_.num_set ()
+ this->ready_set_.ex_mask_.num_set ();
// number_ready > 0 meaning there are handles in the ready_set
// &wait_set != &(this->ready_set_) means that we need to copy
// the handles from the ready_set to the wait set because the
// wait_set_ doesn't contain all the handles in the ready_set_
if (number_ready > 0 && &wait_set != &(this->ready_set_))
{
wait_set.rd_mask_ = this->ready_set_.rd_mask_;
wait_set.wr_mask_ = this->ready_set_.wr_mask_;
wait_set.ex_mask_ = this->ready_set_.ex_mask_;
this->ready_set_.rd_mask_.reset ();
this->ready_set_.wr_mask_.reset ();
this->ready_set_.ex_mask_.reset ();
}
return number_ready;
}
- 将dispatch_set_清空
- wait_for_multiple_events 看ready_set_是否有事件(不需要select),如果有,将ready_set_复制到dispatch_set_,同时将ready_set_清空, 如果ready_set_没有事件,则将wait_set_复制到dispatch_set_,调用select得到内核的就绪事件
- 调用dispatch分发处理就绪事件,先处理中断事件,再处理定时器事件,接着处理通知事件,最后处理io事件,对于io事件处理完后,会设置ready_mask
ACE_Select_Reactor是ACE_Select_Reactor_T模板的一个实例
#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
typedef ACE_Token ACE_SELECT_TOKEN;
#else
typedef ACE_Noop_Token ACE_SELECT_TOKEN;
#endif /* ACE_MT_SAFE && ACE_MT_SAFE != 0 */
typedef ACE_Reactor_Token_T<ACE_SELECT_TOKEN> ACE_Select_Reactor_Token;
typedef ACE_Select_Reactor_T<ACE_Select_Reactor_Token> ACE_Select_Reactor;
ACE_Select_Reactor_Handle_Set:集中管理读,写,异常三个io集
ACE_WFMO_Reactor
使用WaitForMultipleObjects或者WaitForMultipleObjectsEx
atomic_wait_array_ :用于存放lock_和ok_to_wait_
handle_events:调用event_handling
ACE_INLINE int
ACE_WFMO_Reactor::handle_events (ACE_Time_Value *how_long)
{
return this->event_handling (how_long, FALSE);
}
int
ACE_WFMO_Reactor::event_handling (ACE_Time_Value *max_wait_time,
int alertable)
{
ACE_TRACE ("ACE_WFMO_Reactor::event_handling");
// Make sure we are not closed
if (!this->open_for_business_ || this->deactivated_)
{
errno = ESHUTDOWN;
return -1;
}
// Stash the current time -- the destructor of this object will
// automatically compute how much time elapsed since this method was
// called.
ACE_Countdown_Time countdown (max_wait_time);
int result;
do
{
// Check to see if it is ok to enter ::WaitForMultipleObjects
// This will acquire <this->lock_> on success On failure, the
// lock will not be acquired
result = this->ok_to_wait (max_wait_time, alertable);
if (result != 1)
return result;
// Increment the number of active threads
++this->active_threads_;
// Release the <lock_>
this->lock_.release ();
// Update the countdown to reflect time waiting to play with the
// mut and event.
countdown.update ();
// Calculate timeout
int timeout = this->calculate_timeout (max_wait_time);
// Wait for event to happen
DWORD wait_status = this->wait_for_multiple_events (timeout,
alertable);
// Upcall
result = this->safe_dispatch (wait_status);
if (0 == result)
{
// wait_for_multiple_events timed out without dispatching
// anything. Because of rounding and conversion errors and
// such, it could be that the wait loop timed out, but
// the timer queue said it wasn't quite ready to expire a
// timer. In this case, max_wait_time won't have quite been
// reduced to 0, and we need to go around again. If max_wait_time
// is all the way to 0, just return, as the entire time the
// caller wanted to wait has been used up.
countdown.update (); // Reflect time waiting for events
if (0 == max_wait_time || max_wait_time->usec () == 0)
break;
}
}
while (result == 0);
return result;
}
ok_to_wait :调用WaitForMultipleObjects等待lock_和ok_to_wait_
int timeout = max_wait_time == 0 ? INFINITE : max_wait_time->msec ();
DWORD result = 0;
while (1)
{
# if defined (ACE_HAS_PHARLAP)
// PharLap doesn't implement WaitForMultipleObjectsEx, and doesn't
// do async I/O, so it's not needed in this case anyway.
result = ::WaitForMultipleObjects (sizeof this->atomic_wait_array_ / sizeof (ACE_HANDLE),
this->atomic_wait_array_,
TRUE,
timeout);
if (result != WAIT_IO_COMPLETION)
break;
# else
result = ::WaitForMultipleObjectsEx (sizeof this->atomic_wait_array_ / sizeof (ACE_HANDLE),
this->atomic_wait_array_,
TRUE,
timeout,
alertable);
if (result != WAIT_IO_COMPLETION)
break;
# endif /* ACE_HAS_PHARLAP */
}
switch (result)
{
case WAIT_TIMEOUT:
errno = ETIME;
return 0;
case WAIT_FAILED:
case WAIT_ABANDONED_0:
ACE_OS::set_errno_to_last_error ();
return -1;
default:
break;
}
// It is ok to enter ::WaitForMultipleObjects
return 1;
wait_for_multiple_events:等待handler_rep_句柄仓库中的任一事件发生
DWORD
ACE_WFMO_Reactor::wait_for_multiple_events (int timeout,
int alertable)
{
// Wait for any of handles_ to be active, or until timeout expires.
// If <alertable> is enabled allow asynchronous completion of
// ReadFile and WriteFile operations.
#if defined (ACE_HAS_PHARLAP) || defined (ACE_HAS_WINCE)
// PharLap doesn't do async I/O and doesn't implement
// WaitForMultipleObjectsEx, so use WaitForMultipleObjects.
ACE_UNUSED_ARG (alertable);
return ::WaitForMultipleObjects (this->handler_rep_.max_handlep1 (),
this->handler_rep_.handles (),
FALSE,
timeout);
#else
return ::WaitForMultipleObjectsEx (this->handler_rep_.max_handlep1 (),
this->handler_rep_.handles (),
FALSE,
timeout,
alertable);
#endif /* ACE_HAS_PHARLAP */
}
safe_dispatch:事件处理,检查WaitForMultipleObjects 或者WaitForMultipleObjectsEx 的返回状态,状态可能值为
- WAIT_FAILED
- WAIT_TIMEOUT
- WAIT_IO_COMPLETION
- WAIT_OBJECT_0 到 (WAIT_OBJECT_0 + nCount – 1)
- WAIT_ABANDONED_0 (WAIT_ABANDONED_0 + nCount – 1)
dispatch_handles :分发事件处理
dispatch_handler:io事件调用complex_dispatch_handler,信号事件调用simple_dispatch_handler
ACE_INLINE int
ACE_WFMO_Reactor::safe_dispatch (DWORD wait_status)
{
int result = -1;
ACE_SEH_TRY
{
result = this->dispatch (wait_status);
}
ACE_SEH_FINALLY
{
this->update_state ();
}
return result;
}
int
ACE_WFMO_Reactor::dispatch (DWORD wait_status)
{
// Expire timers
int handlers_dispatched = this->expire_timers ();
switch (wait_status)
{
case WAIT_FAILED: // Failure.
ACE_OS::set_errno_to_last_error ();
return -1;
case WAIT_TIMEOUT: // Timeout.
errno = ETIME;
return handlers_dispatched;
#ifndef ACE_HAS_WINCE
case WAIT_IO_COMPLETION: // APC.
return handlers_dispatched;
#endif // ACE_HAS_WINCE
default: // Dispatch.
// We'll let dispatch worry about abandoned mutes.
handlers_dispatched += this->dispatch_handles (wait_status);
return handlers_dispatched;
}
}
int
ACE_WFMO_Reactor::dispatch_handles (DWORD wait_status)
{
// dispatch_slot is the absolute slot. Only += is used to
// increment it.
DWORD dispatch_slot = 0;
// Cache this value, this is the absolute value.
DWORD const max_handlep1 = this->handler_rep_.max_handlep1 ();
// nCount starts off at <max_handlep1>, this is a transient count of
// handles last waited on.
DWORD nCount = max_handlep1;
for (int number_of_handlers_dispatched = 1;
;
++number_of_handlers_dispatched)
{
const bool ok = (
#if ! defined(__BORLANDC__) \
&& !defined (__MINGW32__) \
&& !defined (_MSC_VER)
// wait_status is unsigned in Borland, Green Hills,
// mingw32 and MSVC++
// This >= is always true, with a warning.
wait_status >= WAIT_OBJECT_0 &&
#endif
wait_status <= (WAIT_OBJECT_0 + nCount));
if (ok)
dispatch_slot += wait_status - WAIT_OBJECT_0;
else
// Otherwise, a handle was abandoned.
dispatch_slot += wait_status - WAIT_ABANDONED_0;
// Dispatch handler
if (this->dispatch_handler (dispatch_slot, max_handlep1) == -1)
return -1;
// Increment slot
++dispatch_slot;
// We're done.
if (dispatch_slot >= max_handlep1)
return number_of_handlers_dispatched;
// Readjust nCount
nCount = max_handlep1 - dispatch_slot;
// Check the remaining handles
wait_status = this->poll_remaining_handles (dispatch_slot);
switch (wait_status)
{
case WAIT_FAILED: // Failure.
ACE_OS::set_errno_to_last_error ();
/* FALLTHRU */
case WAIT_TIMEOUT:
// There are no more handles ready, we can return.
return number_of_handlers_dispatched;
}
}
}
int
ACE_WFMO_Reactor::complex_dispatch_handler (DWORD slot,
ACE_HANDLE event_handle)
{
// This dispatch is used for I/O entires.
ACE_WFMO_Reactor_Handler_Repository::Current_Info ¤t_info =
this->handler_rep_.current_info ()[slot];
WSANETWORKEVENTS events;
ACE_Reactor_Mask problems = ACE_Event_Handler::NULL_MASK;
if (::WSAEnumNetworkEvents ((SOCKET) current_info.io_handle_,
event_handle,
&events) == SOCKET_ERROR)
problems = ACE_Event_Handler::ALL_EVENTS_MASK;
else
{
// Prepare for upcalls. Clear the bits from <events> representing
// events the handler is not interested in. If there are any left,
// do the upcall(s). upcall will replace events.lNetworkEvents
// with bits representing any functions that requested a repeat
// callback before checking handles again. In this case, continue
// to call back unless the handler is unregistered as a result of
// one of the upcalls. The way this is written, the upcalls will
// keep being done even if one or more upcalls reported problems.
// In practice this may turn out not so good, but let's see. If any
// problems, please notify Steve Huston <shuston@riverace.com>
// before or after you change this code.
events.lNetworkEvents &= current_info.network_events_;
while (events.lNetworkEvents != 0)
{
ACE_Event_Handler *event_handler =
current_info.event_handler_;
int reference_counting_required =
event_handler->reference_counting_policy ().value () ==
ACE_Event_Handler::Reference_Counting_Policy::ENABLED;
// Call add_reference() if needed.
if (reference_counting_required)
{
event_handler->add_reference ();
}
// Upcall
problems |= this->upcall (current_info.event_handler_,
current_info.io_handle_,
events);
// Call remove_reference() if needed.
if (reference_counting_required)
{
event_handler->remove_reference ();
}
if (this->handler_rep_.scheduled_for_deletion (slot))
break;
}
}
if (problems != ACE_Event_Handler::NULL_MASK
&& !this->handler_rep_.scheduled_for_deletion (slot) )
this->handler_rep_.unbind (event_handle, problems);
return 0;
}
ACE_Reactor_Mask
ACE_WFMO_Reactor::upcall (ACE_Event_Handler *event_handler,
ACE_HANDLE io_handle,
WSANETWORKEVENTS &events)
{
// This method figures out what exactly has happened to the socket
// and then calls appropriate methods.
ACE_Reactor_Mask problems = ACE_Event_Handler::NULL_MASK;
// Go through the events and do the indicated upcalls. If the handler
// doesn't want to be called back, clear the bit for that event.
// At the end, set the bits back to <events> to request a repeat call.
long actual_events = events.lNetworkEvents;
int action;
if (ACE_BIT_ENABLED (actual_events, FD_WRITE))
{
action = event_handler->handle_output (io_handle);
if (action <= 0)
{
ACE_CLR_BITS (actual_events, FD_WRITE);
if (action == -1)
ACE_SET_BITS (problems, ACE_Event_Handler::WRITE_MASK);
}
}
if (ACE_BIT_ENABLED (actual_events, FD_CONNECT))
{
if (events.iErrorCode[FD_CONNECT_BIT] == 0)
{
// Successful connect
action = event_handler->handle_output (io_handle);
if (action <= 0)
{
ACE_CLR_BITS (actual_events, FD_CONNECT);
if (action == -1)
ACE_SET_BITS (problems,
ACE_Event_Handler::CONNECT_MASK);
}
}
// Unsuccessful connect
else
{
action = event_handler->handle_input (io_handle);
if (action <= 0)
{
ACE_CLR_BITS (actual_events, FD_CONNECT);
if (action == -1)
ACE_SET_BITS (problems,
ACE_Event_Handler::CONNECT_MASK);
}
}
}
if (ACE_BIT_ENABLED (actual_events, FD_OOB))
{
action = event_handler->handle_exception (io_handle);
if (action <= 0)
{
ACE_CLR_BITS (actual_events, FD_OOB);
if (action == -1)
ACE_SET_BITS (problems, ACE_Event_Handler::EXCEPT_MASK);
}
}
if (ACE_BIT_ENABLED (actual_events, FD_READ))
{
action = event_handler->handle_input (io_handle);
if (action <= 0)
{
ACE_CLR_BITS (actual_events, FD_READ);
if (action == -1)
ACE_SET_BITS (problems, ACE_Event_Handler::READ_MASK);
}
}
if (ACE_BIT_ENABLED (actual_events, FD_CLOSE)
&& ACE_BIT_DISABLED (problems, ACE_Event_Handler::READ_MASK))
{
action = event_handler->handle_input (io_handle);
if (action <= 0)
{
ACE_CLR_BITS (actual_events, FD_CLOSE);
if (action == -1)
ACE_SET_BITS (problems, ACE_Event_Handler::READ_MASK);
}
}
if (ACE_BIT_ENABLED (actual_events, FD_ACCEPT))
{
action = event_handler->handle_input (io_handle);
if (action <= 0)
{
ACE_CLR_BITS (actual_events, FD_ACCEPT);
if (action == -1)
ACE_SET_BITS (problems, ACE_Event_Handler::ACCEPT_MASK);
}
}
if (ACE_BIT_ENABLED (actual_events, FD_QOS))
{
action = event_handler->handle_qos (io_handle);
if (action <= 0)
{
ACE_CLR_BITS (actual_events, FD_QOS);
if (action == -1)
ACE_SET_BITS (problems, ACE_Event_Handler::QOS_MASK);
}
}
if (ACE_BIT_ENABLED (actual_events, FD_GROUP_QOS))
{
action = event_handler->handle_group_qos (io_handle);
if (action <= 0)
{
ACE_CLR_BITS (actual_events, FD_GROUP_QOS);
if (action == -1)
ACE_SET_BITS (problems, ACE_Event_Handler::GROUP_QOS_MASK);
}
}
events.lNetworkEvents = actual_events;
return problems;
}
int
ACE_WFMO_Reactor::simple_dispatch_handler (DWORD slot,
ACE_HANDLE event_handle)
{
// This dispatch is used for non-I/O entires
// Assign the ``signaled'' HANDLE so that callers can get it.
// siginfo_t is an ACE - specific fabrication. Constructor exists.
siginfo_t sig (event_handle);
ACE_Event_Handler *event_handler =
this->handler_rep_.current_info ()[slot].event_handler_;
int requires_reference_counting =
event_handler->reference_counting_policy ().value () ==
ACE_Event_Handler::Reference_Counting_Policy::ENABLED;
if (requires_reference_counting)
{
event_handler->add_reference ();
}
// Upcall
if (event_handler->handle_signal (0, &sig) == -1)
this->handler_rep_.unbind (event_handle,
ACE_Event_Handler::NULL_MASK);
// Call remove_reference() if needed.
if (requires_reference_counting)
{
event_handler->remove_reference ();
}
return 0;
}
ACE_QtReactor
QtReactor在注册事件处理器时,会通过create_notifiers_for_handle
创建QSocketNotifier
并且将信号activated与read_event ,write_event,exception_event 槽函数连接起来
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);
}
}