public void SetDeviceStatus([NotNull] DeviceStatus status)
        {
            Guard.NotNull(status, nameof(status));

            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    if (deviceMap.ContainsKey(status.DeviceAddress))
                    {
                        DeviceMapEntry existingEntry = deviceMap[status.DeviceAddress];

                        bool hasChanges = existingEntry.ApplyChanges(status);
                        existingEntry.Extend();

                        if (hasChanges)
                        {
                            Log.Debug($"Device {status.DeviceAddress} changed.");
                            DeviceChanged?.Invoke(this, new EventArgs<DeviceStatus>(status));
                        }
                    }
                    else
                    {
                        var newEntry = new DeviceMapEntry(status, RemoveTimerTick);
                        deviceMap[status.DeviceAddress] = newEntry;
                        newEntry.Extend();

                        Log.Debug($"Device {status.DeviceAddress} added.");
                        DeviceAdded?.Invoke(this, new EventArgs<DeviceStatus>(status));
                    }
                }
            }
        }
示例#2
0
        public void Init()
        {
            Tracker = new LockTracker("xxx");
            Now     = DateTimeOffset.Now.AddHours(2);
            Later   = Now.AddHours(4);

            SystemTime.Now = () => Now;
        }
示例#3
0
        public FileEntry([NotNull] string name, [NotNull] DirectoryEntry parent)
            : base(name, FileAttributes.Archive, parent.ChangeTracker, parent.LoggedOnAccount)
        {
            Guard.NotNull(parent, nameof(parent));

            Parent        = parent;
            PathFormatter = new FileEntryPathFormatter(this);
            lockTracker   = new LockTracker(this);

            if (parent.IsEncrypted)
            {
                SetEncrypted();
            }

            CreationTimeUtc = LastWriteTimeUtc = LastAccessTimeUtc = parent.SystemClock.UtcNow();
        }
        public void UpdateMediatorStatus(int mediatorStatus)
        {
            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    if (mediatorStatus != lastMediatorStatus)
                    {
                        Log.Debug($"Mediator status changed from {lastMediatorStatus} to {mediatorStatus}.");

                        lastMediatorStatus = mediatorStatus;
                        MediatorStatusChanged?.Invoke(this, new EventArgs<int>(mediatorStatus));
                    }
                }
            }
        }
        public async Task LockAsync(string key, string subKey, Func <Task> insideLock)
        {
            //Modified version of : http://stackoverflow.com/questions/5578744/doing-locking-in-asp-net-correctly
            //And : https://blog.cdemi.io/async-waiting-inside-c-sharp-locks/
            string      lockKey     = GetLockKey(key, subKey);
            LockTracker lockTracker = _Locks.GetOrAdd(lockKey + "0", k => new LockTracker());

            Interlocked.Increment(ref lockTracker.WaitingThreads);

            try
            {
                await lockTracker.Lock.WaitAsync();
                await insideLock();
            }
            finally
            {
                _Locks.TryRemove(lockKey + Interlocked.Decrement(ref lockTracker.WaitingThreads), out LockTracker _);
                lockTracker.Lock.Release();
            }
        }
        public void Start()
        {
            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    if (hasBeenStarted || hasBeenDisposed)
                    {
                        Log.Debug("Already started or disposed.");
                        return;
                    }
                    hasBeenStarted = true;
                }
            }

            Log.Debug("Creating task for reconnect loop.");
            Task.Factory.StartNew(ReconnectLoop, CancellationToken.None, TaskCreationOptions.LongRunning,
                TaskScheduler.Default).ContinueWith(task => reconnectLoopTerminatedWaitHandle.Set());
        }
        /// <summary>
        /// Pauses the consumer. Blocks until the current action has completed.
        /// </summary>
        public void Pause()
        {
            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    if (!disposeRequested && isConsumerRunning)
                    {
                        isConsumerRunning = false;

                        Log.Debug("Signaling state change after pause.");
                        Monitor.Pulse(stateLock);
                    }
                    else
                    {
                        Log.Debug("Already paused or disposed.");
                    }
                }
            }
        }
        public void Initialize([NotNull] CirceControllerSessionManager sessionManager)
        {
            Guard.NotNull(sessionManager, nameof(sessionManager));

            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    if (circeSessionManager.Value != null)
                    {
                        throw new InvalidOperationException("Already initialized.");
                    }

                    sessionManager.DeviceTracker.DeviceAdded += DeviceTrackerOnDeviceAddedOrChanged;
                    sessionManager.DeviceTracker.DeviceChanged += DeviceTrackerOnDeviceAddedOrChanged;

                    circeSessionManager.Value = sessionManager;
                }
            }
        }
        public void Suspend()
        {
            AssertInitialized();

            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    if (raiseEventsCancellationTokenSource != null)
                    {
                        raiseEventsCancellationTokenSource.Cancel();
                        raiseEventsCancellationTokenSource = null;
                    }

                    syncCancellationSource.Value?.Cancel();
                }
            }
        }
        private void RemoveTimerTick([NotNull] object state)
        {
            try
            {
                using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
                {
                    lock (stateLock)
                    {
                        lockTracker.Acquired();

                        var entry = (DeviceMapEntry) state;

                        WirelessNetworkAddress address = entry.LastStatus.DeviceAddress;
                        if (deviceMap.Remove(address))
                        {
                            Log.Debug($"Device {address} removed.");
                            DeviceRemoved?.Invoke(this, new EventArgs<WirelessNetworkAddress>(address));
                        }
                        entry.Dispose();
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error("Unexpected error while processing removal of wireless device.", ex);
            }
        }
        public void Dispose()
        {
            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    while (deviceMap.Count > 0)
                    {
                        KeyValuePair<WirelessNetworkAddress, DeviceMapEntry> firstPair = deviceMap.First();
                        deviceMap.Remove(firstPair.Key);
                        firstPair.Value.Dispose();
                    }
                }
            }
        }
 public void Init()
 {
     Tracker = new LockTracker("xxx");
 }
        private void HandleNetworkSynchronizationCompleted(ClockSynchronizationResult synchronizationResult)
        {
            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    if (synchronizationResult == ClockSynchronizationResult.Succeeded)
                    {
                        Resume();
                    }

                    networkBeingSynced = null;
                }
            }

            try
            {
                SyncCompleted?.Invoke(this, new ClockSynchronizationCompletedEventArgs(synchronizationResult));
            }
            catch (Exception ex)
            {
                Log.Error($"Failed to handle clock synchronization update for {synchronizationResult}.", ex);
            }
        }
        public void Dispose()
        {
            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    if (!disposeRequested)
                    {
                        disposeRequested = true;

                        Log.Debug("Dispose: Signaling state change after dispose.");
                        Monitor.Pulse(stateLock);

                        workQueue.CompleteAdding();
                    }
                    else
                    {
                        Log.Debug("Already disposed.");
                    }
                }
            }
        }
        public void Dispose()
        {
            // We protect against disposing multiple times sequentially, not concurrently.

            bool disposeAlreadyDone;
            bool mustWaitForReconnectLoopToComplete;

            using (var lockTracker = new LockTracker(Log, "Dispose (pre)"))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    disposeAlreadyDone = hasBeenDisposed;
                    mustWaitForReconnectLoopToComplete = hasBeenStarted;
                }
            }

            if (!disposeAlreadyDone)
            {
                if (mustWaitForReconnectLoopToComplete)
                {
                    Log.Debug("Signaling reconnect loop to terminate.");
                    disposeRequestedWaitHandle.Set();

                    Log.Debug("Waiting until reconnect loop has terminated.");
                    reconnectLoopTerminatedWaitHandle.Wait();
                }

                Log.Debug("Cleaning up wait handles.");
                disposeRequestedWaitHandle.Dispose();
                reconnectLoopTerminatedWaitHandle.Dispose();

                using (var lockTracker = new LockTracker(Log, "Dispose (post)"))
                {
                    lock (stateLock)
                    {
                        lockTracker.Acquired();

                        hasBeenDisposed = true;
                    }
                }
            }
            else
            {
                Log.Debug("Already disposed.");
            }
        }
            public void Accept(NotifyActionOperation operation)
            {
                using (var lockTracker = new LockTracker(InnerLog, MethodBase.GetCurrentMethod()))
                {
                    lock (nonReentrantProcessIncomingOperationLock)
                    {
                        lockTracker.Acquired();

                        owner.HandleIncomingNotifyActionOperation(operation);
                    }
                }
            }
        private void DeviceTrackerOnDeviceAddedOrChanged([CanBeNull] object sender,
            [NotNull] EventArgs<DeviceStatus> eventArgs)
        {
            Guard.NotNull(eventArgs, nameof(eventArgs));

            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    if (!deviceMap.ContainsKey(eventArgs.Argument.DeviceAddress))
                    {
                        deviceMap[eventArgs.Argument.DeviceAddress] = new DeviceSyncStatus();
                    }
                    deviceMap[eventArgs.Argument.DeviceAddress].Update(eventArgs.Argument.ClockSynchronization);

                    if (deviceMap[eventArgs.Argument.DeviceAddress].IsSynchronized && IsSyncInProgress)
                    {
                        VerifySynchronizationComplete();
                    }
                }
            }
        }
        public bool IsDeviceSynchronized([NotNull] WirelessNetworkAddress deviceAddress)
        {
            Guard.NotNull(deviceAddress, nameof(deviceAddress));
            AssertInitialized();

            bool result = false;

            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    if (deviceMap.ContainsKey(deviceAddress))
                    {
                        result = deviceMap[deviceAddress].IsSynchronized;
                    }
                }
            }

            return result;
        }
        public void NotifyDeviceIsAlive([NotNull] WirelessNetworkAddress deviceAddress)
        {
            Guard.NotNull(deviceAddress, nameof(deviceAddress));

            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    if (deviceMap.ContainsKey(deviceAddress))
                    {
                        DeviceMapEntry existingEntry = deviceMap[deviceAddress];
                        existingEntry.Extend();
                    }
                }
            }
        }
        private void ConsumerLoop()
        {
            Log.Debug("Entering ConsumerLoop.");
            foreach (WorkItem workItem in workQueue.GetConsumingEnumerable())
            {
                try
                {
                    if (workItem.CancelToken.IsCancellationRequested)
                    {
                        // Action was canceled (and task was signaled) while waiting in the queue, so ignore it.
                        Log.Debug("Skipping pre-canceled queue entry.");
                        continue;
                    }

                    using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
                    {
                        lock (stateLock)
                        {
                            lockTracker.Acquired();

                            if (!isConsumerRunning && !disposeRequested)
                            {
                                Log.Debug("Entering wait loop until running or disposing.");
                                while (!isConsumerRunning && !disposeRequested)
                                {
                                    // Consumer is paused, so block this thread until state changes.
                                    Monitor.Wait(stateLock);
                                }
                                Log.Debug("Exited wait loop.");
                            }

                            if (disposeRequested)
                            {
                                // Dispose has been called by producer, so cancel whatever is left in the queue.

                                Log.Debug("Disposal has been requested, canceling queue entry.");
                                workItem.TaskSource.TrySetCanceled();
                                continue;
                            }

                            int taskId = workItem.TaskSource.Task.Id;

                            // Perform action inside lock, so that state transitions will block 
                            // until the current action has completed.
                            try
                            {
                                workItem.CancelToken.ThrowIfCancellationRequested();

                                Log.Debug($"Executing action for task {taskId}.");
                                workItem.Action();
                                workItem.TaskSource.TrySetResult(null);
                                Log.Debug("Task completed.");
                            }
                            catch (OperationCanceledException)
                            {
                                Log.Debug($"Propagating cancellation request to task {taskId}.");
                                workItem.TaskSource.TrySetCanceled();
                            }
                            catch (Exception ex)
                            {
                                Log.Debug($"Setting task {taskId} to error state.");
                                workItem.TaskSource.TrySetException(ex);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.Error("Unexpected error in ConsumerLoop.", ex);
                }
            }
            workQueue.Dispose();

            Log.Debug("Leaving ConsumerLoop.");
        }
        public void StartNetworkSynchronization(
            [NotNull] [ItemNotNull] IEnumerable<WirelessNetworkAddress> devicesInNetwork)
        {
            Guard.NotNull(devicesInNetwork, nameof(devicesInNetwork));
            CirceControllerSessionManager sessionManager = AssertInitialized();

            using (var lockTracker = new LockTracker(Log, MethodBase.GetCurrentMethod()))
            {
                lock (stateLock)
                {
                    lockTracker.Acquired();

                    AssertNotSyncInProgress();

                    Suspend();

                    networkBeingSynced = new HashSet<WirelessNetworkAddress>(devicesInNetwork);

                    if (!NetworkContainsSynchronizableDevices())
                    {
                        // Only devices without a clock. No need for sync or raise events for clock re-sync.
                        Task.Factory.StartNew(
                            () => HandleNetworkSynchronizationCompleted(ClockSynchronizationResult.Succeeded),
                            CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
                        return;
                    }

                    ResetDevices();
                }
            }

            syncCancellationSource.Value = new CancellationTokenSource();
            Task invokeOperationTask = sessionManager.SynchronizeClocksAsync(syncCancellationSource.Value.Token);

            invokeOperationTask.ContinueWith(opTask =>
            {
                if (opTask.IsFaulted)
                {
                    Log.Warn("Failed sending SynchronizeClocks operation.", opTask.Exception);
                    HandleNetworkSynchronizationCompleted(ClockSynchronizationResult.Failed);
                }
                else if (opTask.IsCanceled)
                {
                    Log.Warn("Timeout on sending SynchronizeClocks operation.");
                    HandleNetworkSynchronizationCompleted(ClockSynchronizationResult.CanceledOrTimedOut);
                }
                else
                {
                    Task<ClockSynchronizationResult> waitForRepliesTask =
                        WaitForRepliesAsync(syncCancellationSource.Value.Token);

                    waitForRepliesTask.ContinueWith(repliesTask =>
                    {
                        if (repliesTask.IsFaulted)
                        {
                            Log.Warn("Failed waiting for Sync replies.", opTask.Exception);
                            HandleNetworkSynchronizationCompleted(ClockSynchronizationResult.Failed);
                        }
                        else if (repliesTask.IsCanceled)
                        {
                            string succeeded = deviceMap.Any()
                                ? string.Join(", ", deviceMap.Keys.Where(IsDeviceSynchronized))
                                : "(none)";
                            Log.Warn($"Timeout on waiting for Sync Succeeded replies. Devices succeeded: {succeeded}");
                            HandleNetworkSynchronizationCompleted(ClockSynchronizationResult.CanceledOrTimedOut);
                        }
                        else
                        {
                            HandleNetworkSynchronizationCompleted(repliesTask.Result);
                        }
                    }, TaskScheduler.Current);

                    AutoCancelTaskAfterTimeout(waitForRepliesTask, syncCancellationSource.Value);
                }
            }, TaskScheduler.Current);

            AutoCancelTaskAfterTimeout(invokeOperationTask, syncCancellationSource.Value);
        }