//
        // Constructor: registers a take with a blocking queue.
        //

        internal StRegisteredTake(StBlockingQueue <T> queue, StTakeCallback <T> callback,
                                  object cbState, int timeout, bool executeOnce)
        {
            //
            // Validate the arguments.
            //

            if (timeout == 0)
            {
                throw new ArgumentOutOfRangeException("\"timeout\" can not be zero");
            }
            if (callback == null)
            {
                throw new ArgumentOutOfRangeException("\"callback\" must be specified");
            }

            //
            // Initialize the registered take fields.
            //

            this.queue = queue;
            cbparker   = new CbParker(UnparkCallback);
            if ((this.timeout = timeout) != Timeout.Infinite)
            {
                toTimer = new RawTimer(cbparker);
            }
            this.executeOnce = executeOnce;
            this.callback    = callback;
            this.cbState     = cbState;

            //
            // Execute the TryTakePrologue prologue on the queue.
            //

            waitNode = queue.TryTakePrologue(cbparker, StParkStatus.Success, out dataItem,
                                             ref hint);

            //
            // Set the state to active and enable the unpark callback.
            //

            state = ACTIVE;
            int ws;

            if ((ws = cbparker.EnableCallback(timeout, toTimer)) != StParkStatus.Pending)
            {
                //
                // The take operation was already accomplished. To prevent
                // uncontrolled reentrancy, the unpark callback is executed inline.
                //

                UnparkCallback(ws);
            }
        }
        //
        // Exchanges a data item asynchronously. The specified callback gets called
        // when the exchange completes and is passed the received data item.
        //
        //  TODO: Prevent unbounded reentrancy (hacked by queueing to the pool).
        //

        public ExchangeRegistration RegisterExchange(T myData, ExchangeCallback <T> callback,
                                                     object state, int timeout)
        {
            if (timeout == 0)
            {
                throw new ArgumentOutOfRangeException("timeout", "The timeout can't be zero");
            }
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }

            T yourData;

            if (TryExchange(myData, out yourData))
            {
                ThreadPool.QueueUserWorkItem(_ => callback(state, yourData, false));
                return(new ExchangeRegistration());
            }

            state = state ?? this;
            WaitNode wn       = null;
            var      cbparker = new CbParker(ws => {
                if (ws != StParkStatus.Success && xchgPoint == wn)
                {
                    Interlocked.CompareExchange(ref xchgPoint, null, wn);
                }

                if (ws != StParkStatus.WaitCancelled)
                {
                    callback(state, wn.Channel, ws == StParkStatus.Timeout);
                }
            });

            wn = new WaitNode(cbparker, myData);

            if (TryExchange(wn, myData, out yourData))
            {
                ThreadPool.QueueUserWorkItem(_ => callback(state, yourData, false));
                return(new ExchangeRegistration());
            }

            var timer      = timeout != Timeout.Infinite ? new RawTimer(cbparker) : null;
            int waitStatus = cbparker.EnableCallback(timeout, timer);

            if (waitStatus != StParkStatus.Pending)
            {
                ThreadPool.QueueUserWorkItem(_ => callback(state, wn.Channel, waitStatus == StParkStatus.Timeout));
                return(new ExchangeRegistration());
            }
            return(new ExchangeRegistration(cbparker));
        }
Пример #3
0
        //
        // Constructors.
        //

        public StTimer(bool notificationTimer)
        {
            if (notificationTimer)
            {
                tmrEvent = new StNotificationEvent();
            }
            else
            {
                tmrEvent = new StSynchronizationEvent();
            }

            state    = INACTIVE;
            cbparker = new CbParker(TimerCallback);
            timer    = new RawTimer(cbparker);
        }
        //
        // Constructor: registers a wait with a Waitable synchronizer.
        //

        internal StRegisteredWait(StWaitable waitObject, WaitOrTimerCallback callback,
                                  object cbState, int timeout, bool executeOnce)
        {
            //
            // Validate the arguments.
            //

            if (timeout == 0)
            {
                throw new ArgumentOutOfRangeException("\"timeout\" can't be zero");
            }
            if (callback == null)
            {
                throw new ArgumentOutOfRangeException("\"callback\" can't be null");
            }
            if ((waitObject is StReentrantFairLock) || (waitObject is StReentrantReadWriteLock))
            {
                throw new InvalidOperationException("can't register waits on reentrant locks");
            }
            if ((waitObject is StNotificationEvent) && !executeOnce)
            {
                throw new InvalidOperationException("Notification event can't register waits"
                                                    + " to execute more than once");
            }

            //
            // Initialize the register wait fields
            //

            waitable         = waitObject;
            cbparker         = new CbParker(UnparkCallback);
            toTimer          = new RawTimer(cbparker);
            this.timeout     = timeout;
            this.executeOnce = executeOnce;
            this.callback    = callback;
            this.cbState     = (cbState != null) ? cbState : this;

            //
            // Execute the WaitAny prologue on the waitable.
            //
            int ignored = 0;

            waitBlock = waitObject._WaitAnyPrologue(cbparker, StParkStatus.Success, ref hint,
                                                    ref ignored);

            //
            // Set the registered wait state to active and enable the
            // unpark callback.
            //

            state = ACTIVE;
            int ws = cbparker.EnableCallback(timeout, toTimer);

            if (ws != StParkStatus.Pending)
            {
                //
                // The acquire operation was already accomplished. To prevent
                // uncontrolled reentrancy, the unpark callback is executed inline.
                //

                UnparkCallback(ws);
            }
        }