2020-03-24 19:08:37 +01:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
2018-02-13 18:23:53 +01:00
|
|
|
// Licensed under the MIT License.
|
2016-07-14 04:27:37 +02:00
|
|
|
|
|
|
|
#region Using directives
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Management.Automation;
|
|
|
|
using System.Threading;
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
namespace Microsoft.Management.Infrastructure.CimCmdlets
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
|
|
|
/// Async operation base class, it will issue async operation through
|
|
|
|
/// 1...* CimSession object(s), processing the async results, extended
|
|
|
|
/// pssemantics operations, and manage the lifecycle of created
|
|
|
|
/// CimSession object(s).
|
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
|
|
|
internal abstract class CimAsyncOperation : IDisposable
|
|
|
|
{
|
|
|
|
#region Constructor
|
|
|
|
|
|
|
|
/// <summary>
|
2020-11-27 09:07:58 +01:00
|
|
|
/// Initializes a new instance of the <see cref="CimAsyncOperation"/> class.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </summary>
|
2020-11-21 16:07:28 +01:00
|
|
|
protected CimAsyncOperation()
|
2016-07-14 04:27:37 +02:00
|
|
|
{
|
|
|
|
this.moreActionEvent = new ManualResetEventSlim(false);
|
|
|
|
this.actionQueue = new ConcurrentQueue<CimBaseAction>();
|
|
|
|
this._disposed = 0;
|
|
|
|
this.operationCount = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region Event handler
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
|
|
|
/// Handler used to handle new action event from
|
|
|
|
/// <seealso cref="CimSessionProxy"/> object.
|
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="cimSession">
|
|
|
|
/// <seealso cref="CimSession"/> object raised the event
|
|
|
|
/// </param>
|
2018-12-29 04:25:49 +01:00
|
|
|
/// <param name="actionArgs">Event argument.</param>
|
2016-07-14 04:27:37 +02:00
|
|
|
protected void NewCmdletActionHandler(object cimSession, CmdletActionEventArgs actionArgs)
|
|
|
|
{
|
2020-07-10 20:43:41 +02:00
|
|
|
DebugHelper.WriteLogEx("Disposed {0}, action type = {1}", 0, this.Disposed, actionArgs.Action);
|
2016-07-14 04:27:37 +02:00
|
|
|
|
|
|
|
if (this.Disposed)
|
|
|
|
{
|
|
|
|
if (actionArgs.Action is CimSyncAction)
|
|
|
|
{
|
|
|
|
// unblock the thread waiting for response
|
|
|
|
(actionArgs.Action as CimSyncAction).OnComplete();
|
|
|
|
}
|
2018-12-24 07:20:06 +01:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isEmpty = this.actionQueue.IsEmpty;
|
|
|
|
this.actionQueue.Enqueue(actionArgs.Action);
|
|
|
|
if (isEmpty)
|
|
|
|
{
|
|
|
|
this.moreActionEvent.Set();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
|
|
|
/// Handler used to handle new operation event from
|
|
|
|
/// <seealso cref="CimSessionProxy"/> object.
|
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="cimSession">
|
2019-06-20 13:36:49 +02:00
|
|
|
/// <seealso cref="CimSession"/> object raised the event.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </param>
|
2018-12-29 04:25:49 +01:00
|
|
|
/// <param name="actionArgs">Event argument.</param>
|
2016-07-14 04:27:37 +02:00
|
|
|
protected void OperationCreatedHandler(object cimSession, OperationEventArgs actionArgs)
|
|
|
|
{
|
|
|
|
DebugHelper.WriteLogEx();
|
|
|
|
|
2019-06-20 13:36:49 +02:00
|
|
|
lock (this.a_lock)
|
2016-07-14 04:27:37 +02:00
|
|
|
{
|
|
|
|
this.operationCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
|
|
|
/// Handler used to handle operation deletion event from
|
|
|
|
/// <seealso cref="CimSessionProxy"/> object.
|
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="cimSession">
|
2019-06-20 13:36:49 +02:00
|
|
|
/// <seealso cref="CimSession"/> object raised the event.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </param>
|
2018-12-29 04:25:49 +01:00
|
|
|
/// <param name="actionArgs">Event argument.</param>
|
2016-07-14 04:27:37 +02:00
|
|
|
protected void OperationDeletedHandler(object cimSession, OperationEventArgs actionArgs)
|
|
|
|
{
|
|
|
|
DebugHelper.WriteLogEx();
|
|
|
|
|
2019-06-20 13:36:49 +02:00
|
|
|
lock (this.a_lock)
|
2016-07-14 04:27:37 +02:00
|
|
|
{
|
|
|
|
this.operationCount--;
|
|
|
|
if (this.operationCount == 0)
|
|
|
|
{
|
|
|
|
this.moreActionEvent.Set();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
|
|
|
/// process all actions in the action queue
|
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="cmdletOperation">
|
2020-04-14 23:34:53 +02:00
|
|
|
/// Wrapper of cmdlet, <seealso cref="CmdletOperationBase"/> for details.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </param>
|
|
|
|
public void ProcessActions(CmdletOperationBase cmdletOperation)
|
|
|
|
{
|
|
|
|
if (!this.actionQueue.IsEmpty)
|
|
|
|
{
|
|
|
|
CimBaseAction action;
|
|
|
|
while (GetActionAndRemove(out action))
|
|
|
|
{
|
|
|
|
action.Execute(cmdletOperation);
|
|
|
|
if (this.Disposed)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
2020-04-14 23:34:53 +02:00
|
|
|
/// Process remaining actions until all operations are completed or
|
2019-06-20 13:36:49 +02:00
|
|
|
/// current cmdlet is terminated by user.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="cmdletOperation">
|
2020-04-14 23:34:53 +02:00
|
|
|
/// Wrapper of cmdlet, <seealso cref="CmdletOperationBase"/> for details.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </param>
|
|
|
|
public void ProcessRemainActions(CmdletOperationBase cmdletOperation)
|
|
|
|
{
|
|
|
|
DebugHelper.WriteLogEx();
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
ProcessActions(cmdletOperation);
|
|
|
|
if (!this.IsActive())
|
|
|
|
{
|
|
|
|
DebugHelper.WriteLogEx("Either disposed or all operations completed.", 2);
|
|
|
|
break;
|
|
|
|
}
|
2018-12-24 07:20:06 +01:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
this.moreActionEvent.Wait();
|
|
|
|
this.moreActionEvent.Reset();
|
|
|
|
}
|
|
|
|
catch (ObjectDisposedException ex)
|
|
|
|
{
|
|
|
|
// This might happen if this object is being disposed,
|
|
|
|
// while another thread is processing the remaining actions
|
|
|
|
DebugHelper.WriteLogEx("moreActionEvent was disposed: {0}.", 2, ex);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-12-24 07:20:06 +01:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
ProcessActions(cmdletOperation);
|
|
|
|
}
|
|
|
|
|
|
|
|
#region helper methods
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
2019-06-20 13:36:49 +02:00
|
|
|
/// Get action object from action queue.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
2018-12-29 04:25:49 +01:00
|
|
|
/// <param name="action">Next action to execute.</param>
|
2018-12-25 17:43:03 +01:00
|
|
|
/// <returns>True indicates there is an valid action, otherwise false.</returns>
|
2016-07-14 04:27:37 +02:00
|
|
|
protected bool GetActionAndRemove(out CimBaseAction action)
|
|
|
|
{
|
|
|
|
return this.actionQueue.TryDequeue(out action);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
|
|
|
/// Add temporary <seealso cref="CimSessionProxy"/> object to cache.
|
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
2018-12-29 04:25:49 +01:00
|
|
|
/// <param name="sessionproxy">Cimsession wrapper object.</param>
|
2016-07-14 04:27:37 +02:00
|
|
|
protected void AddCimSessionProxy(CimSessionProxy sessionproxy)
|
|
|
|
{
|
|
|
|
lock (cimSessionProxyCacheLock)
|
|
|
|
{
|
2020-07-31 01:06:38 +02:00
|
|
|
if (this.cimSessionProxyCache == null)
|
2016-07-14 04:27:37 +02:00
|
|
|
{
|
|
|
|
this.cimSessionProxyCache = new List<CimSessionProxy>();
|
|
|
|
}
|
2018-12-24 07:20:06 +01:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
if (!this.cimSessionProxyCache.Contains(sessionproxy))
|
|
|
|
{
|
|
|
|
this.cimSessionProxyCache.Add(sessionproxy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
|
|
|
/// Are there active operations?
|
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
2018-12-25 17:43:03 +01:00
|
|
|
/// <returns>True for having active operations, otherwise false.</returns>
|
2016-07-14 04:27:37 +02:00
|
|
|
protected bool IsActive()
|
|
|
|
{
|
|
|
|
DebugHelper.WriteLogEx("Disposed {0}, Operation Count {1}", 2, this.Disposed, this.operationCount);
|
|
|
|
bool isActive = (!this.Disposed) && (this.operationCount > 0);
|
|
|
|
return isActive;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Create <see cref="CimSessionProxy"/> object.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="session"></param>
|
|
|
|
protected CimSessionProxy CreateCimSessionProxy(CimSessionProxy originalProxy)
|
|
|
|
{
|
2020-11-21 15:29:44 +01:00
|
|
|
CimSessionProxy proxy = new(originalProxy);
|
2016-07-14 04:27:37 +02:00
|
|
|
this.SubscribeEventAndAddProxytoCache(proxy);
|
|
|
|
return proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Create <see cref="CimSessionProxy"/> object.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="session"></param>
|
|
|
|
protected CimSessionProxy CreateCimSessionProxy(CimSessionProxy originalProxy, bool passThru)
|
|
|
|
{
|
|
|
|
CimSessionProxy proxy = new CimSessionProxySetCimInstance(originalProxy, passThru);
|
|
|
|
this.SubscribeEventAndAddProxytoCache(proxy);
|
|
|
|
return proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Create <see cref="CimSessionProxy"/> object.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="session"></param>
|
|
|
|
protected CimSessionProxy CreateCimSessionProxy(CimSession session)
|
|
|
|
{
|
2020-11-21 15:29:44 +01:00
|
|
|
CimSessionProxy proxy = new(session);
|
2016-07-14 04:27:37 +02:00
|
|
|
this.SubscribeEventAndAddProxytoCache(proxy);
|
|
|
|
return proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Create <see cref="CimSessionProxy"/> object.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="session"></param>
|
|
|
|
protected CimSessionProxy CreateCimSessionProxy(CimSession session, bool passThru)
|
|
|
|
{
|
|
|
|
CimSessionProxy proxy = new CimSessionProxySetCimInstance(session, passThru);
|
|
|
|
this.SubscribeEventAndAddProxytoCache(proxy);
|
|
|
|
return proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Create <see cref="CimSessionProxy"/> object, and
|
|
|
|
/// add the proxy into cache.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="computerName"></param>
|
|
|
|
protected CimSessionProxy CreateCimSessionProxy(string computerName)
|
|
|
|
{
|
2020-11-21 15:29:44 +01:00
|
|
|
CimSessionProxy proxy = new(computerName);
|
2016-07-14 04:27:37 +02:00
|
|
|
this.SubscribeEventAndAddProxytoCache(proxy);
|
|
|
|
return proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Create <see cref="CimSessionProxy"/> object, and
|
|
|
|
/// add the proxy into cache.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="computerName"></param>
|
|
|
|
/// <param name="cimInstance"></param>
|
|
|
|
/// <returns></returns>
|
2019-06-20 13:36:49 +02:00
|
|
|
protected CimSessionProxy CreateCimSessionProxy(string computerName, CimInstance cimInstance)
|
2016-07-14 04:27:37 +02:00
|
|
|
{
|
2020-11-21 15:29:44 +01:00
|
|
|
CimSessionProxy proxy = new(computerName, cimInstance);
|
2016-07-14 04:27:37 +02:00
|
|
|
this.SubscribeEventAndAddProxytoCache(proxy);
|
|
|
|
return proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Create <see cref="CimSessionProxy"/> object, and
|
|
|
|
/// add the proxy into cache.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="computerName"></param>
|
|
|
|
/// <param name="cimInstance"></param>
|
|
|
|
/// <param name="passThru"></param>
|
|
|
|
protected CimSessionProxy CreateCimSessionProxy(string computerName, CimInstance cimInstance, bool passThru)
|
|
|
|
{
|
|
|
|
CimSessionProxy proxy = new CimSessionProxySetCimInstance(computerName, cimInstance, passThru);
|
|
|
|
this.SubscribeEventAndAddProxytoCache(proxy);
|
|
|
|
return proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2019-01-06 00:40:24 +01:00
|
|
|
/// Subscribe event from proxy and add proxy to cache.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </summary>
|
|
|
|
/// <param name="proxy"></param>
|
|
|
|
protected void SubscribeEventAndAddProxytoCache(CimSessionProxy proxy)
|
|
|
|
{
|
|
|
|
this.AddCimSessionProxy(proxy);
|
|
|
|
SubscribeToCimSessionProxyEvent(proxy);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
|
|
|
/// Subscribe to the events issued by <see cref="CimSessionProxy"/>.
|
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="proxy"></param>
|
|
|
|
protected virtual void SubscribeToCimSessionProxyEvent(CimSessionProxy proxy)
|
|
|
|
{
|
|
|
|
DebugHelper.WriteLogEx();
|
|
|
|
|
|
|
|
proxy.OnNewCmdletAction += this.NewCmdletActionHandler;
|
|
|
|
proxy.OnOperationCreated += this.OperationCreatedHandler;
|
|
|
|
proxy.OnOperationDeleted += this.OperationDeletedHandler;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2019-01-06 00:40:24 +01:00
|
|
|
/// Retrieve the base object out if wrapped in psobject.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </summary>
|
|
|
|
/// <param name="value"></param>
|
|
|
|
/// <returns></returns>
|
|
|
|
protected object GetBaseObject(object value)
|
|
|
|
{
|
|
|
|
PSObject psObject = value as PSObject;
|
2020-07-31 01:06:38 +02:00
|
|
|
if (psObject == null)
|
2016-07-14 04:27:37 +02:00
|
|
|
{
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
object baseObject = psObject.BaseObject;
|
|
|
|
var arrayObject = baseObject as object[];
|
2020-07-31 01:06:38 +02:00
|
|
|
if (arrayObject == null)
|
2016-07-14 04:27:37 +02:00
|
|
|
{
|
|
|
|
return baseObject;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
object[] arraybaseObject = new object[arrayObject.Length];
|
|
|
|
for (int i = 0; i < arrayObject.Length; i++)
|
|
|
|
{
|
|
|
|
arraybaseObject[i] = GetBaseObject(arrayObject[i]);
|
|
|
|
}
|
2018-12-24 07:20:06 +01:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
return arraybaseObject;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Retrieve the reference object or reference array object.
|
|
|
|
/// The returned object has to be either CimInstance or CImInstance[] type,
|
|
|
|
/// if not thrown exception.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="value"></param>
|
2018-12-29 04:25:49 +01:00
|
|
|
/// <param name="referenceType">Output the cimtype of the value, either Reference or ReferenceArray.</param>
|
2020-04-14 23:34:53 +02:00
|
|
|
/// <returns>The object.</returns>
|
2016-07-14 04:27:37 +02:00
|
|
|
protected object GetReferenceOrReferenceArrayObject(object value, ref CimType referenceType)
|
|
|
|
{
|
|
|
|
PSReference cimReference = value as PSReference;
|
|
|
|
if (cimReference != null)
|
|
|
|
{
|
|
|
|
object baseObject = GetBaseObject(cimReference.Value);
|
2020-11-05 17:58:48 +01:00
|
|
|
if (!(baseObject is CimInstance cimInstance))
|
2016-07-14 04:27:37 +02:00
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
2018-12-24 07:20:06 +01:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
referenceType = CimType.Reference;
|
|
|
|
return cimInstance;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
object[] cimReferenceArray = value as object[];
|
2020-07-31 01:06:38 +02:00
|
|
|
if (cimReferenceArray == null)
|
2016-07-14 04:27:37 +02:00
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
2020-08-01 01:41:59 +02:00
|
|
|
else if (cimReferenceArray[0] is not PSReference)
|
2016-07-14 04:27:37 +02:00
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
2018-12-24 07:20:06 +01:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
CimInstance[] cimInstanceArray = new CimInstance[cimReferenceArray.Length];
|
|
|
|
for (int i = 0; i < cimReferenceArray.Length; i++)
|
|
|
|
{
|
2020-11-05 17:58:48 +01:00
|
|
|
if (!(cimReferenceArray[i] is PSReference tempCimReference))
|
2016-07-14 04:27:37 +02:00
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
2018-12-24 07:20:06 +01:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
object baseObject = GetBaseObject(tempCimReference.Value);
|
|
|
|
cimInstanceArray[i] = baseObject as CimInstance;
|
2020-07-31 01:06:38 +02:00
|
|
|
if (cimInstanceArray[i] == null)
|
2016-07-14 04:27:37 +02:00
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2018-12-24 07:20:06 +01:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
referenceType = CimType.ReferenceArray;
|
|
|
|
return cimInstanceArray;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region IDisposable
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
|
|
|
/// Indicates whether this object was disposed or not
|
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
|
|
|
protected bool Disposed
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2020-07-10 20:43:41 +02:00
|
|
|
return this._disposed == 1;
|
2016-07-14 04:27:37 +02:00
|
|
|
}
|
|
|
|
}
|
2018-12-24 07:20:06 +01:00
|
|
|
|
2020-07-10 20:43:41 +02:00
|
|
|
private int _disposed;
|
2016-07-14 04:27:37 +02:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
|
|
|
/// Dispose() calls Dispose(true).
|
|
|
|
/// Implement IDisposable. Do not make this method virtual.
|
|
|
|
/// A derived class should not be able to override this method.
|
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
|
|
|
public void Dispose()
|
|
|
|
{
|
|
|
|
Dispose(true);
|
2019-06-20 13:36:49 +02:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
// This object will be cleaned up by the Dispose method.
|
2016-08-26 22:46:03 +02:00
|
|
|
// Therefore, you should call GC.SuppressFinalize to
|
2016-07-14 04:27:37 +02:00
|
|
|
// take this object off the finalization queue
|
|
|
|
// and prevent finalization code for this object
|
|
|
|
// from executing a second time.
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
|
|
|
/// Dispose(bool disposing) executes in two distinct scenarios.
|
|
|
|
/// If disposing equals true, the method has been called directly
|
|
|
|
/// or indirectly by a user's code. Managed and unmanaged resources
|
|
|
|
/// can be disposed.
|
|
|
|
/// If disposing equals false, the method has been called by the
|
|
|
|
/// runtime from inside the finalizer and you should not reference
|
|
|
|
/// other objects. Only unmanaged resources can be disposed.
|
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
2018-12-28 12:39:06 +01:00
|
|
|
/// <param name="disposing">Whether it is directly called.</param>
|
2016-07-14 04:27:37 +02:00
|
|
|
protected virtual void Dispose(bool disposing)
|
|
|
|
{
|
|
|
|
if (Interlocked.CompareExchange(ref this._disposed, 1, 0) == 0)
|
|
|
|
{
|
|
|
|
if (disposing)
|
|
|
|
{
|
|
|
|
// free managed resources
|
|
|
|
Cleanup();
|
|
|
|
}
|
|
|
|
// free native resources if there are any
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <para>
|
2020-04-14 23:34:53 +02:00
|
|
|
/// Clean up managed resources.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </para>
|
|
|
|
/// </summary>
|
|
|
|
private void Cleanup()
|
|
|
|
{
|
|
|
|
DebugHelper.WriteLogEx();
|
|
|
|
|
|
|
|
// unblock thread that waiting for more actions
|
|
|
|
this.moreActionEvent.Set();
|
|
|
|
CimBaseAction action;
|
|
|
|
while (GetActionAndRemove(out action))
|
|
|
|
{
|
|
|
|
DebugHelper.WriteLog("Action {0}", 2, action);
|
|
|
|
|
|
|
|
if (action is CimSyncAction)
|
|
|
|
{
|
|
|
|
// unblock the thread waiting for response
|
|
|
|
(action as CimSyncAction).OnComplete();
|
|
|
|
}
|
|
|
|
}
|
2018-12-24 07:20:06 +01:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
if (this.cimSessionProxyCache != null)
|
|
|
|
{
|
|
|
|
List<CimSessionProxy> temporaryProxy;
|
|
|
|
lock (this.cimSessionProxyCache)
|
|
|
|
{
|
|
|
|
temporaryProxy = new List<CimSessionProxy>(this.cimSessionProxyCache);
|
|
|
|
this.cimSessionProxyCache.Clear();
|
|
|
|
}
|
2019-06-20 13:36:49 +02:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
// clean up all proxy objects
|
|
|
|
foreach (CimSessionProxy proxy in temporaryProxy)
|
|
|
|
{
|
|
|
|
DebugHelper.WriteLog("Dispose proxy ", 2);
|
|
|
|
proxy.Dispose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.moreActionEvent.Dispose();
|
|
|
|
if (this.ackedEvent != null)
|
|
|
|
{
|
|
|
|
this.ackedEvent.Dispose();
|
|
|
|
}
|
2018-12-24 07:20:06 +01:00
|
|
|
|
2016-07-14 04:27:37 +02:00
|
|
|
DebugHelper.WriteLog("Cleanup complete.", 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region private members
|
|
|
|
|
|
|
|
/// <summary>
|
2019-01-09 22:07:41 +01:00
|
|
|
/// Lock object.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </summary>
|
2020-11-21 15:29:44 +01:00
|
|
|
private readonly object a_lock = new();
|
2016-07-14 04:27:37 +02:00
|
|
|
|
|
|
|
/// <summary>
|
2019-01-09 22:07:41 +01:00
|
|
|
/// Number of active operations.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </summary>
|
2019-06-20 13:36:49 +02:00
|
|
|
private uint operationCount;
|
2016-07-14 04:27:37 +02:00
|
|
|
|
|
|
|
/// <summary>
|
2019-01-06 00:40:24 +01:00
|
|
|
/// Event to notify ps thread that more action is available.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </summary>
|
2020-11-02 08:43:04 +01:00
|
|
|
private readonly ManualResetEventSlim moreActionEvent;
|
2016-07-14 04:27:37 +02:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// The following is the definition of action queue.
|
2016-08-26 22:46:03 +02:00
|
|
|
/// The queue holding all actions to be executed in the context of either
|
2016-07-14 04:27:37 +02:00
|
|
|
/// ProcessRecord or EndProcessing.
|
|
|
|
/// </summary>
|
2020-11-02 08:43:04 +01:00
|
|
|
private readonly ConcurrentQueue<CimBaseAction> actionQueue;
|
2016-07-14 04:27:37 +02:00
|
|
|
|
|
|
|
/// <summary>
|
2019-01-09 22:07:41 +01:00
|
|
|
/// Lock object.
|
2016-07-14 04:27:37 +02:00
|
|
|
/// </summary>
|
2020-11-21 15:29:44 +01:00
|
|
|
private readonly object cimSessionProxyCacheLock = new();
|
2016-07-14 04:27:37 +02:00
|
|
|
|
|
|
|
/// <summary>
|
2019-01-09 22:07:41 +01:00
|
|
|
/// Cache all <see cref="CimSessionProxy"/> objects related to
|
2016-07-14 04:27:37 +02:00
|
|
|
/// the current operation.
|
|
|
|
/// </summary>
|
|
|
|
private List<CimSessionProxy> cimSessionProxyCache;
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region protected members
|
|
|
|
/// <summary>
|
|
|
|
/// Event to notify ps thread that either a ACK message sent back
|
2020-04-14 23:34:53 +02:00
|
|
|
/// or a error happened. Currently only used by
|
2016-07-14 04:27:37 +02:00
|
|
|
/// <see cref="CimRegisterCimIndication"/>.
|
|
|
|
/// </summary>
|
|
|
|
protected ManualResetEventSlim ackedEvent;
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region const strings
|
|
|
|
internal const string ComputerNameArgument = @"ComputerName";
|
|
|
|
internal const string CimSessionArgument = @"CimSession";
|
|
|
|
#endregion
|
2019-01-06 02:51:20 +01:00
|
|
|
}
|
|
|
|
}
|