/// <summary> /// Signals the manager when a logical /// thread has new actions to be processed. /// </summary> /// <param name="thread">The thread with new actions to be processed.</param> internal void SignalItemHandler(LogicalThread thread) { if (thread.TryActivate()) { m_logicalThreads.Enqueue(thread); ActivatePhysicalThread(); } }
/// <summary> /// Signals the manager when a logical /// thread has new actions to be processed. /// </summary> /// <param name="thread">The thread with new actions to be processed.</param> /// <param name="priority">The priority at which the thread is being signaled.</param> internal void SignalItemHandler(LogicalThread thread, int priority) { if (thread.TryActivate(priority)) { Enqueue(thread); ActivatePhysicalThread(); } }
/// <summary> /// Creates a new instance of the <see cref="LogicalThreadOperation"/> class. /// </summary> /// <param name="thread">The thread on which to execute the operation's action.</param> /// <param name="action">The action to be executed.</param> /// <param name="priority">The priority with which the action should be executed on the logical thread.</param> /// <param name="autoRunIfPending"> /// Set to <c>true</c> to execute <see cref="RunIfPending"/> automatically; otherwise, /// set to <c>false</c> for user controlled call timing. /// </param> /// <exception cref="ArgumentException"><paramref name="priority"/> is outside the range between 1 and <see cref="LogicalThread.PriorityLevels"/>.</exception> public LogicalThreadOperation(LogicalThread thread, Action action, int priority, bool autoRunIfPending = true) { m_thread = thread; m_action = action; Priority = priority; m_autoRunIfPending = autoRunIfPending; // Initialize this class with a cancelled token so that // calls to EnsurePriority before the first call to // ExecuteActionAsync do not inadvertently queue actions m_cancellationToken = new CancellationToken(); m_cancellationToken.Cancel(); }
/// <summary> /// Signals the manager when a logical /// thread has new actions to be processed. /// </summary> /// <param name="thread">The thread with new actions to be processed.</param> /// <param name="priority">The priority at which the thread is being signaled.</param> internal void SignalItemHandler(LogicalThread thread, int priority) { if (thread.TryActivate(priority)) { // Make sure the thread has an action to be processed because // another thread could have processed all remaining actions and // deactivated the thread right before the call to TryActivate() if (!thread.HasAction) { thread.Deactivate(); return; } Enqueue(thread); ActivatePhysicalThread(); } }
/// <summary> /// Queues the given thread for execution. /// </summary> /// <param name="thread">The thread to be queued for execution.</param> private void Enqueue(LogicalThread thread) { ICancellationToken executionToken; int activePriority; int nextPriority; do { // Create the execution token to be used in the closure ICancellationToken nextExecutionToken = new CancellationToken(); // Always update the thread's active priority before // the execution token to mitigate race conditions nextPriority = thread.NextPriority; thread.ActivePriority = nextPriority; thread.NextExecutionToken = nextExecutionToken; // Now that the action can be cancelled by another thread using the // new cancellation token, it should be safe to put it in the queue m_logicalThreadQueues[PriorityLevels - nextPriority].Enqueue(() => { if (nextExecutionToken.Cancel()) { return(thread); } return(null); }); // Because enqueuing the thread is a multi-step process, we need to // double-check in case the thread's priority changed in the meantime activePriority = thread.ActivePriority; nextPriority = thread.NextPriority; // We can use the cancellation token we just created because we only // really need to double-check the work that was done on this thread; // in other words, if another thread changed the priority in the // meantime, it can double-check its own work executionToken = nextExecutionToken; }while (activePriority != nextPriority && executionToken.Cancel()); }
/// <summary> /// Posts the <paramref name="continuation"/> back to the current context. /// </summary> /// <param name="continuation">The action to invoke asynchronously.</param> /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null.</exception> public void OnCompleted(Action continuation) { if (continuation is null) { throw new ArgumentNullException(nameof(continuation)); } LogicalThread thread = Awaitable.Thread ?? new LogicalThread(); int priority = Awaitable.Priority; if (priority > 0) { thread.Push(priority, continuation); } else { thread.Push(continuation); } }
/// <summary> /// Creates an awaitable that ensures the continuation is running on the logical thread. /// </summary> /// <param name="thread">The thread to join.</param> /// <param name="priority">The priority of the continuation when completing asynchronously.</param> /// <returns>A context that, when awaited, runs on the logical thread.</returns> public static LogicalThreadAwaitable Join(this LogicalThread thread, int priority) => new LogicalThreadAwaitable(thread, priority);
/// <summary> /// Creates an awaitable that ensures the continuation is running on the logical thread. /// </summary> /// <param name="thread">The thread to join.</param> /// <returns>A context that, when awaited, runs on the logical thread.</returns> public static LogicalThreadAwaitable Join(this LogicalThread thread) => new LogicalThreadAwaitable(thread);
// Gets the thread used to process data for // the meter identified by the given asset key. private LogicalThread GetThread(string meterKey) { if ((object)meterKey == null) return m_noMeterThread ?? (m_noMeterThread = m_meterDataScheduler.CreateThread()); return m_meterDataThreadLookup.GetOrAdd(meterKey, key => { LogicalThread newThread = m_meterDataScheduler.CreateThread(); newThread.UnhandledException += (sender, args) => { Exception ex = args.Argument; if (ex is FileSkippedException) { Log.Warn(ex.Message); return; } string message = $"Exception occurred processing data from meter \"{meterKey}\": {ex.Message}"; OnProcessException(new Exception(message, ex)); }; return newThread; }); }
/// <summary> /// Initializes a new instance of the <see cref="ServiceHelper"/> class. /// </summary> public ServiceHelper() { m_telnetSessionPassword = "******"; m_logStatusUpdates = DefaultLogStatusUpdates; m_maxStatusUpdatesLength = DefaultMaxStatusUpdatesLength; m_maxStatusUpdatesFrequency = DefaultMaxStatusUpdatesFrequency; m_monitorServiceHealth = DefaultMonitorServiceHealth; m_healthMonitorInterval = DefaultHealthMonitorInterval; m_requestHistoryLimit = DefaultRequestHistoryLimit; m_supportFileManagementCommands = DefaultSupportFileManagementCommands; m_supportTelnetSessions = DefaultSupportTelnetSessions; m_supportSystemCommands = DefaultSupportSystemCommands; m_secureRemoteInteractions = DefaultSecureRemoteInteractions; m_serializationFormat = DefaultSerializationFormat; m_persistSettings = DefaultPersistSettings; m_settingsCategory = DefaultSettingsCategory; m_processes = new List<ServiceProcess>(); m_remoteClients = new List<ClientInfo>(); m_clientRequestHistory = new List<ClientRequestInfo>(); m_serviceComponents = new List<object>(); m_clientRequestHandlers = new List<ClientRequestHandler>(); m_componentEnabledStates = new Dictionary<ISupportLifecycle, bool>(); m_clientStatusUpdateLookup = new Dictionary<Guid, ClientStatusUpdateConfiguration>(); m_threadScheduler = new LogicalThreadScheduler(); m_threadScheduler.UnhandledException += LogicalThread_ProcessException; m_statusUpdateThread = m_threadScheduler.CreateThread(2); m_statusUpdateQueue = new List<StatusUpdate>(); // Components m_statusLog = new LogFile(); m_statusLog.FileName = "StatusLog.txt"; m_statusLog.SettingsCategory = "StatusLog"; m_statusLog.LogException += StatusLog_LogException; m_processScheduler = new ScheduleManager(); m_processScheduler.SettingsCategory = "ProcessScheduler"; m_processScheduler.ScheduleDue += Scheduler_ScheduleDue; m_errorLogger = new ErrorLogger(); m_errorLogger.ExitOnUnhandledException = false; m_errorLogger.SettingsCategory = "ErrorLogger"; m_errorLogger.ErrorLog.SettingsCategory = "ErrorLog"; m_errorLogger.LoggingException += ErrorLogger_LoggingException; }
/// <summary> /// Creates a new instance of the <see cref="LogicalThreadOperation"/> class. /// </summary> /// <param name="thread">The thread on which to execute the operation's action.</param> /// <param name="action">The action to be executed.</param> /// <param name="autoRunIfPending"> /// Set to <c>true</c> to execute <see cref="RunIfPending"/> automatically; otherwise, /// set to <c>false</c> for user controlled call timing. /// </param> public LogicalThreadOperation(LogicalThread thread, Action action, bool autoRunIfPending = true) : this(thread, action, 1, autoRunIfPending) { }
/// <summary> /// Creates a new instance of the <see cref="FileProcessor"/> class. /// </summary> /// <param name="processorID">Identifies the file processor so that it can locate its processed file cache.</param> public FileProcessor(Guid processorID) { m_processorID = processorID; m_filter = DefaultFilter; m_filterMethod = filePath => true; m_trackChanges = DefaultTrackChanges; m_cachePath = DefaultCachePath; m_internalBufferSize = DefaultInternalBufferSize; m_maxFragmentation = DefaultMaxFragmentation; m_enumerationStrategy = DefaultEnumerationStrategy; m_fileWatchersLock = new object(); m_fileWatchers = new List<SafeFileWatcher>(); m_threadScheduler = new LogicalThreadScheduler(); m_threadScheduler.UnhandledException += (sender, args) => OnError(args.Argument); m_processingThread = m_threadScheduler.CreateThread(2); m_watcherThread = m_threadScheduler.CreateThread(); m_fileWatchTimer = new Timer(15000); m_fileWatchTimer.Elapsed += FileWatchTimer_Elapsed; m_waitObject = new ManualResetEvent(false); m_touchedFiles = new Dictionary<string, DateTime>(StringComparer.OrdinalIgnoreCase); m_processedFiles = new FileBackedHashSet<string>(Path.Combine(m_cachePath, m_processorID.ToString()), StringComparer.OrdinalIgnoreCase); // Create the enumerator last since we are passing // a reference to 'this' into its constructor m_enumerator = new FileEnumerator(this); }
/// <summary> /// Creates a new instance of the <see cref="FileEnumerator"/> class. /// </summary> /// <param name="fileProcessor">The file processor that created the file enumerator.</param> public FileEnumerator(FileProcessor fileProcessor) { m_fileProcessor = fileProcessor; m_cancellationTokens = new Dictionary<string, CancellationToken>(); m_sequentialEnumerationThread = m_fileProcessor.m_threadScheduler.CreateThread(); m_isActive = new LogicalThreadLocal<bool>(); m_wrapperStack = new LogicalThreadLocal<Stack<Action>>(() => new Stack<Action>()); m_directoryQueue = new LogicalThreadLocal<Queue<Action>>(() => new Queue<Action>()); m_cleanProcessedFilesThread = m_fileProcessor.m_threadScheduler.CreateThread(); m_cleanProcessedFilesOperation = new LogicalThreadOperation(m_cleanProcessedFilesThread, GetProcessedFiles, false); }
/// <summary> /// Creates an awaitable that asynchronously yields /// to a new action on the logical thread when awaited. /// </summary> /// <param name="thread">The thread to yield to.</param> /// <returns>A context that, when awaited, will transition to a new action on the logical thread.</returns> public static LogicalThreadAwaitable Yield(this LogicalThread thread) => new LogicalThreadAwaitable(thread, forceYield: true);
/// <summary> /// Creates an awaitable that asynchronously yields /// to a new action on the logical thread when awaited. /// </summary> /// <param name="thread">The thread to yield to.</param> /// <param name="priority">The priority of the continuation.</param> /// <returns>A context that, when awaited, will transition to a new action on the logical thread.</returns> public static LogicalThreadAwaitable Yield(this LogicalThread thread, int priority) => new LogicalThreadAwaitable(thread, priority, true);
/// <summary> /// Creates a new instance of the <see cref="LogicalThreadAwaitable"/> class. /// </summary> /// <param name="thread">The thread on which to push continuations.</param> /// <param name="priority">The priority of continuations pushed to the thread.</param> /// <param name="forceYield">Force continuations to complete asynchronously.</param> public LogicalThreadAwaitable(LogicalThread thread, int priority = 0, bool forceYield = false) { Thread = thread; Priority = priority; ForceYield = forceYield; }
public ClientStatusUpdateConfiguration(Guid clientID, ServiceHelper serviceHelper) { m_clientID = clientID; m_filter = new ClientFilter(); m_thread = serviceHelper.m_threadScheduler.CreateThread(2); m_messageCounts = new List<Tuple<DateTime, int>>(); m_serviceHelper = serviceHelper; }