/// <summary>
        /// Runs the poller on the caller's thread. Only returns when <see cref="Stop"/> or <see cref="StopAsync"/> are called from another thread.
        /// </summary>
        private void RunPoller()
        {
            try
            {
                // Recalculate all timers now
                foreach (var timer in m_timers)
                {
                    if (timer.Enable)
                    {
                        timer.When = Clock.NowMs() + timer.Interval;
                    }
                }

                // Run until stop is requested
                while (!m_stopSignaler.IsStopRequested)
                {
                    if (m_isPollSetDirty)
                    {
                        RebuildPollset();
                    }

                    var pollStart = Clock.NowMs();

                    // Set tickless to "infinity"
                    long tickless = pollStart + int.MaxValue;

                    // Find the When-value of the earliest timer..
                    foreach (var timer in m_timers)
                    {
                        // If it is enabled but no When is set yet,
                        if (timer.When == -1 && timer.Enable)
                        {
                            // Set this timer's When to now plus it's Interval.
                            timer.When = pollStart + timer.Interval;
                        }

                        // If it has a When and that is earlier than the earliest found thus far,
                        if (timer.When != -1 && tickless > timer.When)
                        {
                            // save that value.
                            tickless = timer.When;
                        }
                    }

                    // Compute a timeout value - how many milliseconds from now that the earliest-timer will expire.
                    var timeout = tickless - pollStart;

                    // Use zero to indicate it has already expired.
                    if (timeout < 0)
                    {
                        timeout = 0;
                    }

                    var isItemAvailable = false;

                    if (m_pollSet.Length != 0)
                    {
                        isItemAvailable = m_netMqSelector.Select(m_pollSet, m_pollSet.Length, timeout);
                    }
                    else if (timeout > 0)
                    {
                        //TODO: Do we really want to simply sleep and return, doing nothing during this interval?
                        //TODO: Should a large value be passed it will sleep for a month literally.
                        //      Solution should be different, but sleep is more natural here than in selector (timers are not selector concern).
                        Debug.Assert(timeout <= int.MaxValue);
                        Thread.Sleep((int)timeout);
                    }

                    // Get the expected end time in case we time out. This looks redundant but, unfortunately,
                    // it happens that Poll takes slightly less than the requested time and 'Clock.NowMs() >= timer.When'
                    // may not true, even if it is supposed to be. In other words, even when Poll times out, it happens
                    // that 'Clock.NowMs() < pollStart + timeout'
                    var expectedPollEnd = !isItemAvailable ? pollStart + timeout : -1L;

                    // that way we make sure we can continue the loop if new timers are added.
                    // timers cannot be removed
                    foreach (var timer in m_timers)
                    {
                        if ((Clock.NowMs() >= timer.When || expectedPollEnd >= timer.When) && timer.When != -1)
                        {
                            timer.InvokeElapsed(this);

                            if (timer.Enable)
                            {
                                timer.When = Clock.NowMs() + timer.Interval;
                            }
                        }
                    }

                    for (var i = 0; i < m_pollSet.Length; i++)
                    {
                        NetMQSelector.Item item = m_pollSet[i];

                        if (item.Socket != null)
                        {
                            NetMQSocket socket = m_pollact[i];

                            if (item.ResultEvent.HasError())
                            {
                                if (++socket.Errors > 1)
                                {
                                    Remove(socket);
                                    item.ResultEvent = PollEvents.None;
                                }
                            }
                            else
                            {
                                socket.Errors = 0;
                            }

                            if (item.ResultEvent != PollEvents.None)
                            {
                                socket.InvokeEvents(this, item.ResultEvent);
                            }
                        }
                        else if (item.ResultEvent.HasError() || item.ResultEvent.HasIn())
                        {
                            if (m_pollinSockets.TryGetValue(item.FileDescriptor, out Action <Socket> action))
                            {
                                action(item.FileDescriptor);
                            }
                        }
                    }
                }

#if !NET35
                // Try to dequeue and execute all pending tasks before stopping poller
                while (m_tasksQueue.TryDequeue(out Task task, TimeSpan.Zero))
                {
                    TryExecuteTask(task);
                }
#endif
            }
            finally
            {
                foreach (var socket in m_sockets.ToList())
                {
                    Remove(socket);
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Poll as long as the given Func evaluates to true.
        /// </summary>
        /// <param name="condition">a Func that returns a boolean value, to evaluate on each poll-iteration to decide when to exit the loop</param>
        /// <exception cref="ObjectDisposedException">This poller must not have already been disposed.</exception>
        /// <exception cref="InvalidOperationException">This poller must not have already been started.</exception>
        private void PollWhile([NotNull, InstantHandle] Func <bool> condition)
        {
            if (m_disposed)
            {
                throw new ObjectDisposedException("Poller is disposed");
            }

            if (m_isStarted)
            {
                throw new InvalidOperationException("Poller is started");
            }

            if (Thread.CurrentThread.Name == null)
            {
                Thread.CurrentThread.Name = "NetMQPollerThread";
            }

            m_isStoppedEvent.Reset();
            m_isStarted = true;
            try
            {
                // the sockets may have been created in another thread, to make sure we can fully use them we do full memory barrier
                // at the beginning of the loop
                Thread.MemoryBarrier();

                // Recalculate all timers now
                foreach (var timer in m_timers)
                {
                    if (timer.Enable)
                    {
                        timer.When = Clock.NowMs() + timer.Interval;
                    }
                }

                // Do this until the given Func evaluates to false...
                while (condition())
                {
                    if (m_isDirty)
                    {
                        RebuildPollset();
                    }

                    var pollStart = Clock.NowMs();
                    var timeout   = TicklessTimer();

                    var isItemsAvailable = false;

                    if (m_pollSize > 0)
                    {
                        isItemsAvailable = m_selector.Select(m_pollset, m_pollSize, timeout);
                    }
                    else
                    {
                        // Don't pass anything less than 0 to sleep or risk an out of range exception or worse - infinity. Do not sleep on 0 from orginal code.
                        if (timeout > 0)
                        {
                            //TODO: Do we really want to simply sleep and return, doing nothing during this interval?
                            //TODO: Should a large value be passed it will sleep for a month literaly.
                            //      Solution should be different, but sleep is more natural here than in selector (timers are not selector concern).
                            Thread.Sleep(timeout);
                        }
                    }

                    // Get the expected end time in case we time out. This looks redundant but, unfortunately,
                    // it happens that Poll takes slightly less than the requested time and 'Clock.NowMs() >= timer.When'
                    // may not true, even if it is supposed to be. In other words, even when Poll times out, it happens
                    // that 'Clock.NowMs() < pollStart + timeout'
                    var expectedPollEnd = !isItemsAvailable ? pollStart + timeout : -1;

                    // that way we make sure we can continue the loop if new timers are added.
                    // timers cannot be removed
                    int timersCount = m_timers.Count;
                    for (int i = 0; i < timersCount; i++)
                    {
                        var timer = m_timers[i];

                        if ((Clock.NowMs() >= timer.When || expectedPollEnd >= timer.When) && timer.When != -1)
                        {
                            timer.InvokeElapsed(this);

                            if (timer.Enable)
                            {
                                timer.When = timer.Interval + Clock.NowMs();
                            }
                        }
                    }

                    for (int itemNbr = 0; itemNbr < m_pollSize; itemNbr++)
                    {
                        SelectItem item = m_pollset[itemNbr];

                        if (item.Socket != null)
                        {
                            NetMQSocket socket = m_pollact[itemNbr];

                            if (item.ResultEvent.HasError())
                            {
                                socket.Errors++;

                                if (socket.Errors > 1)
                                {
                                    RemoveSocket(socket);
                                    item.ResultEvent = PollEvents.None;
                                }
                            }
                            else
                            {
                                socket.Errors = 0;
                            }

                            if (item.ResultEvent != PollEvents.None)
                            {
                                socket.InvokeEvents(this, item.ResultEvent);
                            }
                        }
                        else
                        {
                            if (item.ResultEvent.HasError() || item.ResultEvent.HasIn())
                            {
                                Action <Socket> action;

                                if (m_pollinSockets.TryGetValue(item.FileDescriptor, out action))
                                {
                                    action(item.FileDescriptor);
                                }
                            }
                        }
                    }

                    if (m_zombies.Count > 0)
                    {
                        // Now handle any timer zombies
                        // This is going to be slow if we have many zombies
                        foreach (var netMQTimer in m_zombies)
                        {
                            m_timers.Remove(netMQTimer);
                        }

                        m_zombies.Clear();
                    }
                }
            }
            finally
            {
                try
                {
                    foreach (var socket in m_sockets.ToList())
                    {
                        RemoveSocket(socket);
                    }
                }
                finally
                {
                    m_isStarted = false;
                    m_isStoppedEvent.Set();
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Runs the poller on the caller's thread. Only returns when <see cref="Stop"/> or <see cref="StopAsync"/> are called from another thread.
        /// </summary>
        public void Run()
        {
            CheckDisposed();
            if (IsRunning)
            {
                throw new InvalidOperationException("NetMQPoller is already running");
            }

#if NET35
            m_pollerThread = Thread.CurrentThread;
#else
            var oldSynchronisationContext = SynchronizationContext.Current;
            SynchronizationContext.SetSynchronizationContext(new NetMQSynchronizationContext(this));
            m_isSchedulerThread.Value = true;
#endif
            m_stopSignaler.Reset();

            m_switch.SwitchOn();
            try
            {
                // the sockets may have been created in another thread, to make sure we can fully use them we do full memory barrier
                // at the beginning of the loop
                Thread.MemoryBarrier();

                // Recalculate all timers now
                foreach (var timer in m_timers)
                {
                    if (timer.Enable)
                    {
                        timer.When = Clock.NowMs() + timer.Interval;
                    }
                }

                // Run until stop is requested
                while (!m_stopSignaler.IsStopRequested)
                {
                    if (m_isPollSetDirty)
                    {
                        RebuildPollset();
                    }

                    var pollStart = Clock.NowMs();

                    // Set tickless to "infinity"
                    long tickless = pollStart + int.MaxValue;

                    // Find the When-value of the earliest timer..
                    foreach (var timer in m_timers)
                    {
                        // If it is enabled but no When is set yet,
                        if (timer.When == -1 && timer.Enable)
                        {
                            // Set this timer's When to now plus it's Interval.
                            timer.When = pollStart + timer.Interval;
                        }

                        // If it has a When and that is earlier than the earliest found thus far,
                        if (timer.When != -1 && tickless > timer.When)
                        {
                            // save that value.
                            tickless = timer.When;
                        }
                    }

                    // Compute a timeout value - how many milliseconds from now that that earliest-timer will expire.
                    var timeout = tickless - pollStart;

                    // Use zero to indicate it has already expired.
                    if (timeout < 0)
                    {
                        timeout = 0;
                    }

                    var isItemAvailable = false;

                    if (m_pollSet.Length != 0)
                    {
                        isItemAvailable = m_selector.Select(m_pollSet, m_pollSet.Length, timeout);
                    }
                    else if (timeout > 0)
                    {
                        //TODO: Do we really want to simply sleep and return, doing nothing during this interval?
                        //TODO: Should a large value be passed it will sleep for a month literally.
                        //      Solution should be different, but sleep is more natural here than in selector (timers are not selector concern).
                        Debug.Assert(timeout <= int.MaxValue);
                        Thread.Sleep((int)timeout);
                    }

                    // Get the expected end time in case we time out. This looks redundant but, unfortunately,
                    // it happens that Poll takes slightly less than the requested time and 'Clock.NowMs() >= timer.When'
                    // may not true, even if it is supposed to be. In other words, even when Poll times out, it happens
                    // that 'Clock.NowMs() < pollStart + timeout'
                    var expectedPollEnd = !isItemAvailable ? pollStart + timeout : -1L;

                    // that way we make sure we can continue the loop if new timers are added.
                    // timers cannot be removed
                    foreach (var timer in m_timers)
                    {
                        if ((Clock.NowMs() >= timer.When || expectedPollEnd >= timer.When) && timer.When != -1)
                        {
                            timer.InvokeElapsed(this);

                            if (timer.Enable)
                            {
                                timer.When = Clock.NowMs() + timer.Interval;
                            }
                        }
                    }

                    for (var i = 0; i < m_pollSet.Length; i++)
                    {
                        SelectItem item = m_pollSet[i];

                        if (item.Socket != null)
                        {
                            NetMQSocket socket = m_pollact[i];

                            if (item.ResultEvent.HasError())
                            {
                                if (++socket.Errors > 1)
                                {
                                    Remove(socket);
                                    item.ResultEvent = PollEvents.None;
                                }
                            }
                            else
                            {
                                socket.Errors = 0;
                            }

                            if (item.ResultEvent != PollEvents.None)
                            {
                                socket.InvokeEvents(this, item.ResultEvent);
                            }
                        }
                        else if (item.ResultEvent.HasError() || item.ResultEvent.HasIn())
                        {
                            Action <Socket> action;
                            if (m_pollinSockets.TryGetValue(item.FileDescriptor, out action))
                            {
                                action(item.FileDescriptor);
                            }
                        }
                    }
                }
            }
            finally
            {
                try
                {
                    foreach (var socket in m_sockets.ToList())
                    {
                        Remove(socket);
                    }
                }
                finally
                {
#if NET35
                    m_pollerThread = null;
#else
                    m_isSchedulerThread.Value = false;
                    SynchronizationContext.SetSynchronizationContext(oldSynchronisationContext);
#endif
                    m_switch.SwitchOff();
                }
            }
        }
Esempio n. 4
0
        private void PollWhile(Func <bool> condition)
        {
            if (m_disposed)
            {
                throw new ObjectDisposedException("Poller is disposed");
            }

            if (m_isStarted)
            {
                throw new InvalidOperationException("Poller is started");
            }

            if (Thread.CurrentThread.Name == null)
            {
                Thread.CurrentThread.Name = "NetMQPollerThread";
            }

            m_isStoppedEvent.Reset();
            m_isStarted = true;
            try
            {
                // the sockets may have been created in another thread, to make sure we can fully use them we do full memory barried
                // at the begining of the loop
                Thread.MemoryBarrier();

                //  Recalculate all timers now
                foreach (NetMQTimer netMQTimer in m_timers)
                {
                    if (netMQTimer.Enable)
                    {
                        netMQTimer.When = Clock.NowMs() + netMQTimer.Interval;
                    }
                }

                while (condition())
                {
                    if (m_isDirty)
                    {
                        RebuildPollset();
                    }

                    var pollStart = Clock.NowMs();
                    var timeout   = TicklessTimer();

                    var nbEvents = ZMQ.Poll(m_pollset, m_pollSize, timeout);

                    // Get the expected end time in case we time out. This looks redundant but, unfortunately,
                    // it happens that Poll takes slightly less than the requested time and 'Clock.NowMs() >= timer.When'
                    // may not true, even if it is supposed to be. In other words, even when Poll times out, it happens
                    // that 'Clock.NowMs() < pollStart + timeout'
                    var expectedPollEnd = nbEvents == 0 ? pollStart + timeout : -1;

                    // that way we make sure we can continue the loop if new timers are added.
                    // timers cannot be removed
                    int timersCount = m_timers.Count;
                    for (int i = 0; i < timersCount; i++)
                    {
                        var timer = m_timers[i];

                        if ((Clock.NowMs() >= timer.When || expectedPollEnd >= timer.When) && timer.When != -1)
                        {
                            timer.InvokeElapsed(this);

                            if (timer.Enable)
                            {
                                timer.When = timer.Interval + Clock.NowMs();
                            }
                        }
                    }

                    for (int itemNbr = 0; itemNbr < m_pollSize; itemNbr++)
                    {
                        PollItem item = m_pollset[itemNbr];

                        if (item.Socket != null)
                        {
                            NetMQSocket socket = m_pollact[itemNbr] as NetMQSocket;

                            if (item.ResultEvent.HasFlag(PollEvents.PollError) && !socket.IgnoreErrors)
                            {
                                socket.Errors++;

                                if (socket.Errors > 1)
                                {
                                    RemoveSocket(socket);
                                    item.ResultEvent = PollEvents.None;
                                }
                            }
                            else
                            {
                                socket.Errors = 0;
                            }

                            if (item.ResultEvent != PollEvents.None)
                            {
                                socket.InvokeEvents(this, item.ResultEvent);
                            }
                        }
                        else
                        {
                            if (item.ResultEvent.HasFlag(PollEvents.PollError) || item.ResultEvent.HasFlag(PollEvents.PollIn))
                            {
                                Action <Socket> action;

                                if (m_pollinSockets.TryGetValue(item.FileDescriptor, out action))
                                {
                                    action(item.FileDescriptor);
                                }
                            }
                        }
                    }

                    if (m_zombies.Any())
                    {
                        //  Now handle any timer zombies
                        //  This is going to be slow if we have many zombies
                        foreach (NetMQTimer netMQTimer in m_zombies)
                        {
                            m_timers.Remove(netMQTimer);
                        }

                        m_zombies.Clear();
                    }
                }
            }
            finally
            {
                m_isStoppedEvent.Set();

                foreach (var socket in m_sockets.ToList())
                {
                    RemoveSocket(socket);
                }
            }
        }
Esempio n. 5
0
        public void Start()
        {
            Thread.CurrentThread.Name = "NetMQPollerThread";

            m_isStoppedEvent.Reset();
            m_isStarted = true;
            try
            {
                // the sockets may have been created in another thread, to make sure we can fully use them we do full memory barried
                // at the begining of the loop
                Thread.MemoryBarrier();

                //  Recalculate all timers now
                foreach (NetMQTimer netMQTimer in m_timers)
                {
                    if (netMQTimer.Enable)
                    {
                        netMQTimer.When = Clock.NowMs() + netMQTimer.Interval;
                    }
                }

                while (!m_cancellationTokenSource.IsCancellationRequested)
                {
                    if (m_isDirty)
                    {
                        RebuildPollset();
                    }

                    ZMQ.Poll(m_pollset, m_pollSize, TicklessTimer());

                    // that way we make sure we can continue the loop if new timers are added.
                    // timers cannot be removed
                    int timersCount = m_timers.Count;
                    for (int i = 0; i < timersCount; i++)
                    {
                        var timer = m_timers[i];

                        if (Clock.NowMs() >= timer.When && timer.When != -1)
                        {
                            timer.InvokeElapsed(this);

                            if (timer.Enable)
                            {
                                timer.When = timer.Interval + Clock.NowMs();
                            }
                        }
                    }

                    for (int itemNbr = 0; itemNbr < m_pollSize; itemNbr++)
                    {
                        NetMQSocket socket = m_pollact[itemNbr];
                        PollItem    item   = m_pollset[itemNbr];

                        if (item.ResultEvent.HasFlag(PollEvents.PollError) && !socket.IgnoreErrors)
                        {
                            socket.Errors++;

                            if (socket.Errors > 1)
                            {
                                RemoveSocket(socket);
                                item.ResultEvent = PollEvents.None;
                            }
                        }
                        else
                        {
                            socket.Errors = 0;
                        }

                        if (item.ResultEvent != PollEvents.None)
                        {
                            socket.InvokeEvents(this, item.ResultEvent);
                        }
                    }

                    if (m_zombies.Any())
                    {
                        //  Now handle any timer zombies
                        //  This is going to be slow if we have many zombies
                        foreach (NetMQTimer netMQTimer in m_zombies)
                        {
                            m_timers.Remove(netMQTimer);
                        }

                        m_zombies.Clear();
                    }
                }
            }
            finally
            {
                m_isStoppedEvent.Set();
            }
        }