bool SyncChannel::ShouldContinueFromTimeout() { AssertWorkerThread(); mMonitor.AssertCurrentThreadOwns(); bool cont; { MonitorAutoUnlock unlock(mMonitor); cont = static_cast<SyncListener*>(mListener)->OnReplyTimeout(); } if (!cont) { // NB: there's a sublety here. If parents were allowed to // send sync messages to children, then it would be possible // for this synchronous close-on-timeout to race with async // |OnMessageReceived| tasks arriving from the child, posted // to the worker thread's event loop. This would complicate // cleanup of the *Channel. But since IPDL forbids this (and // since it doesn't support children timing out on parents), // the parent can only block on RPC messages to the child, and // in that case arriving async messages are enqueued to the // RPC channel's special queue. They're then ignored because // the channel state changes to ChannelTimeout // (i.e. !Connected). SynchronouslyClose(); mChannelState = ChannelTimeout; } return cont; }
void AsyncChannel::CloseWithError() { AssertWorkerThread(); MonitorAutoLock lock(*mMonitor); if (ChannelConnected != mChannelState) { return; } SynchronouslyClose(); mChannelState = ChannelError; PostErrorNotifyTask(); }
void AsyncChannel::Close() { AssertWorkerThread(); { // n.b.: We increase the ref count of monitor temporarily // for the duration of this block. Otherwise, the // function NotifyMaybeChannelError() will call // ::Clear() which can free the monitor. nsRefPtr<RefCountedMonitor> monitor(mMonitor); MonitorAutoLock lock(*monitor); if (ChannelError == mChannelState || ChannelTimeout == mChannelState) { // See bug 538586: if the listener gets deleted while the // IO thread's NotifyChannelError event is still enqueued // and subsequently deletes us, then the error event will // also be deleted and the listener will never be notified // of the channel error. if (mListener) { MonitorAutoUnlock unlock(*monitor); NotifyMaybeChannelError(); } return; } if (ChannelConnected != mChannelState) // XXX be strict about this until there's a compelling reason // to relax NS_RUNTIMEABORT("Close() called on closed channel!"); AssertWorkerThread(); // notify the other side that we're about to close our socket SendSpecialMessage(new GoodbyeMessage()); SynchronouslyClose(); } NotifyChannelClosed(); }