/// <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); } }
private void AddNotificationSocket(SortedDictionary <int, DomainSocketWatcher.Entry > entries, DomainSocketWatcher.FdSet fdSet) { entries[notificationSockets[1].fd] = new DomainSocketWatcher.Entry(notificationSockets [1], new DomainSocketWatcher.NotificationHandler(this)); try { notificationSockets[1].refCount.Reference(); } catch (IOException e) { throw new RuntimeException(e); } fdSet.Add(notificationSockets[1].fd); if (Log.IsTraceEnabled()) { Log.Trace(this + ": adding notificationSocket " + notificationSockets[1].fd + ", connected to " + notificationSockets[0].fd); } }
/// <exception cref="System.IO.IOException"/> private static int DoPoll0(int maxWaitMs, DomainSocketWatcher.FdSet readFds) { }
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(); } } }
/// <summary> /// Send callback, and if the domain socket was closed as a result of /// processing, then also remove the entry for the file descriptor. /// </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> private void SendCallbackAndRemove(string caller, SortedDictionary <int, DomainSocketWatcher.Entry > entries, DomainSocketWatcher.FdSet fdSet, int fd) { if (SendCallback(caller, entries, fdSet, fd)) { Collections.Remove(entries, fd); } }