Example #1
0
        /// <summary>
        /// Create a task that waits until this code can be executed.
        /// It may be cancelled if this code is supposed to be cancelled before it is started
        /// </summary>
        /// <returns>Lock to maintain while the code is being executed internally</returns>
        /// <exception cref="OperationCanceledException">Code has been cancelled</exception>
        private Task <IDisposable> WaitForExecution()
        {
            // Assign a cancellation token if required
            if (CancellationToken == default)
            {
                lock (_cancellationTokenSources)
                {
                    CancellationToken = _cancellationTokenSources[(int)Channel].Token;
                }
            }

            // Codes from interceptors do not have any order control to avoid deadlocks
            Code codeBeingIntercepted = CodeInterception.GetCodeBeingIntercepted(Connection);

            if (codeBeingIntercepted != null)
            {
                if (codeBeingIntercepted.Flags.HasFlag(CodeFlags.IsFromMacro))
                {
                    Flags |= CodeFlags.IsFromMacro;
                    File   = codeBeingIntercepted.File;
                    Macro  = codeBeingIntercepted.Macro;
                }
                return(Task.FromResult <IDisposable>(null));
            }

            // Wait for pending high priority codes
            if (Flags.HasFlag(CodeFlags.IsPrioritized))
            {
                _codeType = InternalCodeType.Prioritized;
                _logger.Debug("Waiting for execution of {0} (prioritized)", this);
                return(_codeStartLocks[(int)Channel, (int)InternalCodeType.Prioritized].LockAsync(CancellationToken));
            }

            // Wait for pending codes from the current macro
            if (Flags.HasFlag(CodeFlags.IsFromMacro))
            {
                _codeType = InternalCodeType.Macro;
                _logger.Debug("Waiting for execution of {0} (macro code)", this);
                return((Macro == null) ? _codeStartLocks[(int)Channel, (int)InternalCodeType.Macro].LockAsync(CancellationToken) : Macro.WaitForCodeStart());
            }

            // Wait for pending codes for message acknowledgements
            // FIXME M0/M1 are not meant to be used while a message box is open
            if (!Flags.HasFlag(CodeFlags.IsFromFirmware) && Interface.IsWaitingForAcknowledgement(Channel) &&
                (Type != CodeType.MCode || (MajorNumber != 0 && MajorNumber != 1)))
            {
                _codeType = InternalCodeType.Acknowledgement;
                _logger.Debug("Waiting for execution of {0} (acknowledgement)", this);
                return(_codeStartLocks[(int)Channel, (int)InternalCodeType.Acknowledgement].LockAsync(CancellationToken));
            }

            // Wait for pending regular codes
            _codeType = InternalCodeType.Regular;
            _logger.Debug("Waiting for execution of {0}", this);
            return(_codeStartLocks[(int)Channel, (int)InternalCodeType.Regular].LockAsync(CancellationToken));
        }
Example #2
0
        /// <summary>
        /// Start the next available G/M/T-code and wait until this code may finish
        /// </summary>
        /// <returns>Awaitable disposable</returns>
        private AwaitableDisposable <IDisposable> WaitForFinish()
        {
            if (!Flags.HasFlag(CodeFlags.Unbuffered))
            {
                StartNextCode();
            }

            if (CodeInterception.IsInterceptingConnection(Connection))
            {
                return(new AwaitableDisposable <IDisposable>(Task.FromResult <IDisposable>(null)));
            }

            AwaitableDisposable <IDisposable> finishTask = (Macro == null) ? _codeFinishLocks[(int)Channel, (int)_codeType].LockAsync(CancellationToken) : Macro.WaitForCodeFinish();

            return(finishTask);
        }