Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
DispatchTable.cs192 linesDownload Raw Back to common
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Threading;6 7using Dbg = System.Management.Automation.Diagnostics;8 9namespace System.Management.Automation.Remoting10{11    /// <summary>12    /// The ServerDispatchTable class.13    /// </summary>14    internal class ServerDispatchTable : DispatchTable<RemoteHostResponse>15    {16        // DispatchTable specialized for RemoteHostResponse.17    }18 19    /// <summary>20    /// Provides a thread-safe dictionary that maps call-ids to AsyncData objects.21    /// When a thread tries to do a get on a hashtable key (callId) that has not been22    /// set it is blocked. Once the key's value is set the thread is released. This is23    /// used to synchronize server calls with their responses.24    ///25    /// This code needs to be thread-safe. The locking convention is that only the26    /// internal or public methods use locks and are thread-safe. The private methods27    /// do not use locks and are not thread-safe (unless called by the internal and28    /// public methods). If the private methods becomes internal or public29    /// please review the locking.30    /// </summary>31    internal class DispatchTable<T> where T : class32    {33        /// <summary>34        /// Response async objects.35        /// </summary>36        private readonly Dictionary<long, AsyncObject<T>> _responseAsyncObjects = new Dictionary<long, AsyncObject<T>>();37 38        /// <summary>39        /// Next call id.40        /// </summary>41        private long _nextCallId = 0;42 43        /// <summary>44        /// Void call id.45        /// </summary>46        internal const long VoidCallId = -100;47 48        /// <summary>49        /// Create new call id.50        /// </summary>51        internal long CreateNewCallId()52        {53            // Note: Only CreateNewCallId adds new records.54 55            long callId = Interlocked.Increment(ref _nextCallId);56            AsyncObject<T> responseAsyncObject = new AsyncObject<T>();57            lock (_responseAsyncObjects)58            {59                _responseAsyncObjects[callId] = responseAsyncObject;60            }61 62            return callId;63        }64 65        /// <summary>66        /// Get response async object.67        /// </summary>68        private AsyncObject<T> GetResponseAsyncObject(long callId)69        {70            AsyncObject<T> responseAsyncObject = null;71            Dbg.Assert(_responseAsyncObjects.ContainsKey(callId), "Expected _responseAsyncObjects.ContainsKey(callId)");72            responseAsyncObject = _responseAsyncObjects[callId];73            Dbg.Assert(responseAsyncObject != null, "Expected responseAsyncObject != null");74            return responseAsyncObject;75        }76 77        /// <summary>78        /// Waits for response PSObject to be set and then returns it. Returns null79        /// if wait was aborted.80        /// </summary>81        /// <param name="callId">82        /// </param>83        /// <param name="defaultValue">84        /// default return value (in case the remote end did not send response).85        /// </param>86        internal T GetResponse(long callId, T defaultValue)87        {88            // Note: Only GetResponse removes records.89 90            AsyncObject<T> responseAsyncObject = null;91            lock (_responseAsyncObjects)92            {93                responseAsyncObject = GetResponseAsyncObject(callId);94            }95 96            // This will block until Value is set on this AsyncObject.97            T remoteHostResponse = responseAsyncObject.Value;98 99            // Remove table entry to conserve memory: this table could be alive for a long time.100            lock (_responseAsyncObjects)101            {102                _responseAsyncObjects.Remove(callId);103            }104 105            // return caller specified value in case there is no response106            // from remote end.107            if (remoteHostResponse == null)108            {109                return defaultValue;110            }111 112            return remoteHostResponse;113        }114 115        /// <summary>116        /// Set response.117        /// </summary>118        internal void SetResponse(long callId, T remoteHostResponse)119        {120            Dbg.Assert(remoteHostResponse != null, "Expected remoteHostResponse != null");121            lock (_responseAsyncObjects)122            {123                // The response-async-object might not exist if the call was aborted by Ctrl-C or if124                // the call had a void return and no return value was expected.125                if (!_responseAsyncObjects.ContainsKey(callId))126                {127                    return;128                }129 130                // Unblock the AsyncObject by setting its value.131                AsyncObject<T> responseAsyncObject = GetResponseAsyncObject(callId);132                responseAsyncObject.Value = remoteHostResponse;133            }134        }135 136        /// <summary>137        /// Abort call.138        /// </summary>139        private void AbortCall(long callId)140        {141            // The response-async-object might not exist if the call was already aborted.142            if (!_responseAsyncObjects.ContainsKey(callId))143            {144                return;145            }146 147            // Releases blocked thread by setting null as return value, which should be detected by caller of GetResponse.148            AsyncObject<T> responseAsyncObject = GetResponseAsyncObject(callId);149            responseAsyncObject.Value = null;150        }151 152        /// <summary>153        /// Abort calls.154        /// </summary>155        private void AbortCalls(List<long> callIds)156        {157            // Releases blocked thread by setting null as return value, which should be detected by caller of GetResponse.158            foreach (long callId in callIds)159            {160                AbortCall(callId);161            }162        }163 164        /// <summary>165        /// Get all calls.166        /// </summary>167        private List<long> GetAllCalls()168        {169            // Gets all the callIds that are waiting on calls.170            List<long> callIds = new List<long>();171            foreach (KeyValuePair<long, AsyncObject<T>> callIdResponseAsyncObjectPair in _responseAsyncObjects)172            {173                callIds.Add(callIdResponseAsyncObjectPair.Key);174            }175 176            return callIds;177        }178 179        /// <summary>180        /// Abort all calls.181        /// </summary>182        internal void AbortAllCalls()183        {184            lock (_responseAsyncObjects)185            {186                List<long> callIds = GetAllCalls();187                AbortCalls(callIds);188            }189        }190    }191}192