//****************************************************************************************************** // ServiceProcess.cs - Gbtc // // Copyright © 2012, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 09/13/2006 - Pinal C. Patel // Generated original version of source code. // 09/30/2008 - J. Ritchie Carroll // Converted to C#. // 03/03/2009 - Pinal C. Patel // Edited code comments. // 09/14/2009 - Stephen C. Wills // Added new header and license agreement. // 12/20/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using System.Text; using System.Threading; using GSF.Units; namespace GSF.ServiceProcess { #region [ Enumerations ] /// /// Indicates the current state of . /// public enum ServiceProcessState { /// /// has not been started. /// Unprocessed, /// /// is currently executing. /// Processing, /// /// has completed processing. /// Processed, /// /// was aborted. /// Aborted, /// /// stopped due to exception. /// Exception } #endregion /// /// Represents a process that executes asynchronously inside a . /// /// public class ServiceProcess : IDisposable, IProvideStatus { #region [ Members ] //Events /// /// Occurs when the of the changes. /// public event EventHandler StateChanged; // Fields #if ThreadTracking private ManagedThread m_processThread; #else private Thread m_processThread; #endif private string m_name; private object[] m_arguments; private Action m_executionMethod; private ServiceProcessState m_currentState; private DateTime m_executionStartTime; private DateTime m_executionStopTime; private bool m_disposed; #endregion #region [ Constructors ] /// /// Initializes a new instance of the class. /// /// that gets invoked when is called. /// Name of the . /// Arguments to be passed in to the . public ServiceProcess(Action executionMethod, string name, params object[] arguments) { m_name = name; m_arguments = arguments; m_executionMethod = executionMethod; m_currentState = ServiceProcessState.Unprocessed; } /// /// Releases the unmanaged resources before the object is reclaimed by . /// ~ServiceProcess() { Dispose(false); } #endregion #region [ Properties ] /// /// Gets or sets the name of the . /// /// The value being assigned is a null or empty string. public string Name { get { return m_name; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value)); m_name = value; } } /// /// Gets or sets the arguments to be passed in to the . /// public object[] Arguments { get { return m_arguments; } set { m_arguments = value; } } /// /// Gets or sets the that gets invoked when is called. /// /// /// Argument1 gets the of the .
/// Argument2 gets the of the . ///
public Action ExecutionMethod { get { return m_executionMethod; } set { m_executionMethod = value; } } /// /// Gets the current . /// public ServiceProcessState CurrentState { get { return m_currentState; } private set { m_currentState = value; OnStateChanged(); // Notify of the change in state. } } /// /// Gets the when execution of last started. /// public DateTime ExecutionStartTime => m_executionStartTime; /// /// Gets the when execution of last completed. /// public DateTime ExecutionStopTime => m_executionStopTime; /// /// Gets the taken by the during the last execution. /// public Time LastExecutionTime => Ticks.ToSeconds(m_executionStopTime.Ticks - m_executionStartTime.Ticks); /// /// Gets the descriptive status of the . /// public string Status { get { StringBuilder status = new StringBuilder(); status.Append(" Process Name: "); status.Append(m_name); status.AppendLine(); status.Append(" Current State: "); status.Append(m_currentState.ToString()); status.AppendLine(); status.Append(" Execution Start Time: "); if (m_executionStartTime != DateTime.MinValue) { status.Append(m_executionStartTime.ToString()); } else { status.Append("N/A"); } status.AppendLine(); status.Append(" Execution Stop Time: "); if (m_executionStopTime != DateTime.MinValue) { status.Append(m_executionStopTime); } else { status.Append("N/A"); } status.AppendLine(); status.Append(" Last Execution Duration: "); status.Append(LastExecutionTime.ToString(3)); status.AppendLine(); return status.ToString(); } } #endregion #region [ Methods ] /// /// Starts the execution of . /// public void Start() { Start(m_arguments); } /// /// Starts the execution of . /// /// Arguments to be passed in to the . public void Start(object[] arguments) { // Start the execution on a separate thread. #if ThreadTracking m_processThread = new ManagedThread(InvokeExecutionMethod); m_processThread.Name = "GSF.ServiceProcess.ServiceProcess.InvokeExecutionMethod() [" + m_name + "]"; #else m_processThread = new Thread(InvokeExecutionMethod); #endif m_processThread.Start(arguments); } /// /// Stops the execution of if it executing. /// public void Abort() { // We'll abort the process only if it is currently executing. if (m_processThread != null) { if (m_processThread.IsAlive) m_processThread.Abort(); } m_processThread = null; } /// /// Releases all the resources used by the object. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Releases the unmanaged resources used by the and optionally releases the managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (!m_disposed) { try { // This will be done regardless of whether the object is finalized or disposed. Abort(); if (disposing) { // This will be done only when the object is disposed by calling Dispose(). m_executionMethod = null; } } finally { m_disposed = true; // Prevent duplicate dispose. } } } /// /// Raises the event. /// protected virtual void OnStateChanged() { if (StateChanged != null) StateChanged(this, EventArgs.Empty); } private void InvokeExecutionMethod(object state) { if (m_executionMethod != null) { CurrentState = ServiceProcessState.Processing; m_executionStartTime = DateTime.UtcNow; m_executionStopTime = DateTime.MinValue; try { // We'll keep the invocation of the delegate in Try...Catch to absorb any exceptions that // were not handled by the consumer. m_executionMethod(m_name, state as object[]); CurrentState = ServiceProcessState.Processed; } catch (ThreadAbortException) { CurrentState = ServiceProcessState.Aborted; } catch (Exception) { // We'll absorb any exceptions if unhandled by the client. CurrentState = ServiceProcessState.Exception; } finally { m_executionStopTime = DateTime.UtcNow; } } m_processThread = null; } #endregion } }