/// <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();
                    }
                }
            }