/// <summary> /// Send callback and return whether or not the domain socket was closed as a /// result of processing. /// </summary> /// <param name="caller">reason for call</param> /// <param name="entries">mapping of file descriptor to entry</param> /// <param name="fdSet">set of file descriptors</param> /// <param name="fd">file descriptor</param> /// <returns>true if the domain socket was closed as a result of processing</returns> private bool SendCallback(string caller, SortedDictionary <int, DomainSocketWatcher.Entry > entries, DomainSocketWatcher.FdSet fdSet, int fd) { if (Log.IsTraceEnabled()) { Log.Trace(this + ": " + caller + " starting sendCallback for fd " + fd); } DomainSocketWatcher.Entry entry = entries[fd]; Preconditions.CheckNotNull(entry, this + ": fdSet contained " + fd + ", which we were " + "not tracking."); DomainSocket sock = entry.GetDomainSocket(); if (entry.GetHandler().Handle(sock)) { if (Log.IsTraceEnabled()) { Log.Trace(this + ": " + caller + ": closing fd " + fd + " at the request of the handler." ); } if (Collections.Remove(toRemove, fd) != null) { if (Log.IsTraceEnabled()) { Log.Trace(this + ": " + caller + " : sendCallback processed fd " + fd + " in toRemove." ); } } try { sock.refCount.UnreferenceCheckClosed(); } catch (IOException) { Preconditions.CheckArgument(false, this + ": file descriptor " + sock.fd + " was closed while " + "still in the poll(2) loop."); } IOUtils.Cleanup(Log, sock); fdSet.Remove(fd); return(true); } else { if (Log.IsTraceEnabled()) { Log.Trace(this + ": " + caller + ": sendCallback not " + "closing fd " + fd); } return(false); } }
/// <summary>Add a socket.</summary> /// <param name="sock"> /// The socket to add. It is an error to re-add a socket that /// we are already watching. /// </param> /// <param name="handler"> /// The handler to associate with this socket. This may be /// called any time after this function is called. /// </param> public void Add(DomainSocket sock, DomainSocketWatcher.Handler handler) { Lock.Lock(); try { if (closed) { handler.Handle(sock); IOUtils.Cleanup(Log, sock); return; } DomainSocketWatcher.Entry entry = new DomainSocketWatcher.Entry(sock, handler); try { sock.refCount.Reference(); } catch (ClosedChannelException) { // If the socket is already closed before we add it, invoke the // handler immediately. Then we're done. handler.Handle(sock); return; } toAdd.AddItem(entry); Kick(); while (true) { try { processedCond.Await(); } catch (Exception) { Thread.CurrentThread().Interrupt(); } if (!toAdd.Contains(entry)) { break; } } } finally { Lock.Unlock(); } }
public void Run() { if (DomainSocketWatcher.Log.IsDebugEnabled()) { DomainSocketWatcher.Log.Debug(this + ": starting with interruptCheckPeriodMs = " + this._enclosing.interruptCheckPeriodMs); } SortedDictionary <int, DomainSocketWatcher.Entry> entries = new SortedDictionary <int , DomainSocketWatcher.Entry>(); DomainSocketWatcher.FdSet fdSet = new DomainSocketWatcher.FdSet(); this._enclosing.AddNotificationSocket(entries, fdSet); try { while (true) { this._enclosing.Lock.Lock(); try { foreach (int fd in fdSet.GetAndClearReadableFds()) { this._enclosing.SendCallbackAndRemove("getAndClearReadableFds", entries, fdSet, fd ); } if (!(this._enclosing.toAdd.IsEmpty() && this._enclosing.toRemove.IsEmpty())) { // Handle pending additions (before pending removes). for (IEnumerator <DomainSocketWatcher.Entry> iter = this._enclosing.toAdd.GetEnumerator (); iter.HasNext();) { DomainSocketWatcher.Entry entry = iter.Next(); DomainSocket sock = entry.GetDomainSocket(); DomainSocketWatcher.Entry prevEntry = entries[sock.fd] = entry; Preconditions.CheckState(prevEntry == null, this + ": tried to watch a file descriptor that we " + "were already watching: " + sock); if (DomainSocketWatcher.Log.IsTraceEnabled()) { DomainSocketWatcher.Log.Trace(this + ": adding fd " + sock.fd); } fdSet.Add(sock.fd); iter.Remove(); } // Handle pending removals while (true) { KeyValuePair <int, DomainSocket> entry = this._enclosing.toRemove.FirstEntry(); if (entry == null) { break; } this._enclosing.SendCallbackAndRemove("handlePendingRemovals", entries, fdSet, entry .Value.fd); } this._enclosing.processedCond.SignalAll(); } // Check if the thread should terminate. Doing this check now is // easier than at the beginning of the loop, since we know toAdd and // toRemove are now empty and processedCond has been notified if it // needed to be. if (this._enclosing.closed) { if (DomainSocketWatcher.Log.IsDebugEnabled()) { DomainSocketWatcher.Log.Debug(this.ToString() + " thread terminating."); } return; } // Check if someone sent our thread an InterruptedException while we // were waiting in poll(). if (Thread.Interrupted()) { throw new Exception(); } } finally { this._enclosing.Lock.Unlock(); } DomainSocketWatcher.DoPoll0(this._enclosing.interruptCheckPeriodMs, fdSet); } } catch (Exception) { DomainSocketWatcher.Log.Info(this.ToString() + " terminating on InterruptedException" ); } catch (Exception e) { DomainSocketWatcher.Log.Error(this.ToString() + " terminating on exception", e); } finally { this._enclosing.Lock.Lock(); try { this._enclosing.Kick(); // allow the handler for notificationSockets[0] to read a byte foreach (DomainSocketWatcher.Entry entry in entries.Values) { // We do not remove from entries as we iterate, because that can // cause a ConcurrentModificationException. this._enclosing.SendCallback("close", entries, fdSet, entry.GetDomainSocket().fd); } entries.Clear(); fdSet.Close(); } finally { this._enclosing.Lock.Unlock(); } } }