1 //---------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //---------------------------------------------------------------- 4 namespace System.ServiceModel.Discovery 5 { 6 using System; 7 using System.Collections.Generic; 8 using System.Runtime; 9 using System.Threading; 10 using System.Xml; 11 using SR2 = System.ServiceModel.Discovery.SR; 12 13 class AsyncOperationLifetimeManager 14 { 15 [Fx.Tag.SynchronizationObject()] 16 object thisLock; 17 18 bool isAborted; 19 AsyncWaitHandle closeHandle; 20 Dictionary<UniqueId, AsyncOperationContext> activeOperations; 21 AsyncOperationLifetimeManager()22 public AsyncOperationLifetimeManager() 23 { 24 this.thisLock = new object(); 25 this.activeOperations = new Dictionary<UniqueId, AsyncOperationContext>(); 26 } 27 28 public bool IsAborted 29 { 30 get 31 { 32 return this.isAborted; 33 } 34 } 35 36 public bool IsClosed 37 { 38 get 39 { 40 return this.closeHandle != null; 41 } 42 } 43 TryAdd(AsyncOperationContext context)44 public bool TryAdd(AsyncOperationContext context) 45 { 46 Fx.Assert(context != null, "The context must be non null."); 47 48 lock (this.thisLock) 49 { 50 if (this.IsAborted || this.IsClosed) 51 { 52 return false; 53 } 54 if (this.activeOperations.ContainsKey(context.OperationId)) 55 { 56 return false; 57 } 58 this.activeOperations.Add(context.OperationId, context); 59 } 60 61 return true; 62 } 63 Abort()64 public AsyncOperationContext[] Abort() 65 { 66 AsyncOperationContext[] retValue = null; 67 bool setCloseHandle = false; 68 69 lock (this.thisLock) 70 { 71 if (this.IsAborted) 72 { 73 return new AsyncOperationContext[] { }; 74 } 75 else 76 { 77 this.isAborted = true; 78 } 79 80 retValue = new AsyncOperationContext[this.activeOperations.Count]; 81 this.activeOperations.Values.CopyTo(retValue, 0); 82 this.activeOperations.Clear(); 83 setCloseHandle = this.closeHandle != null; 84 } 85 86 if (setCloseHandle) 87 { 88 this.closeHandle.Set(); 89 } 90 91 return retValue; 92 } 93 TryLookup(UniqueId operationId, out AsyncOperationContext context)94 public bool TryLookup(UniqueId operationId, out AsyncOperationContext context) 95 { 96 bool success; 97 98 lock (this.thisLock) 99 { 100 success = this.activeOperations.TryGetValue(operationId, out context); 101 } 102 103 return success; 104 } 105 106 public bool TryLookup<T>(UniqueId operationId, out T context) where T : AsyncOperationContext 107 { 108 AsyncOperationContext asyncContext = null; 109 if (TryLookup(operationId, out asyncContext)) 110 { 111 context = asyncContext as T; 112 if (context != null) 113 { 114 return true; 115 } 116 } 117 118 context = null; 119 return false; 120 } 121 122 public T Remove<T>(UniqueId operationId) where T : AsyncOperationContext 123 { 124 AsyncOperationContext context = null; 125 bool setCloseHandle = false; 126 127 lock (this.thisLock) 128 { 129 if ((this.activeOperations.TryGetValue(operationId, out context)) && 130 (context is T)) 131 { 132 this.activeOperations.Remove(operationId); 133 setCloseHandle = (this.closeHandle != null) && (this.activeOperations.Count == 0); 134 } 135 else 136 { 137 context = null; 138 } 139 } 140 141 if (setCloseHandle) 142 { 143 this.closeHandle.Set(); 144 } 145 146 return context as T; 147 } 148 TryRemoveUnique(object userState, out AsyncOperationContext context)149 public bool TryRemoveUnique(object userState, out AsyncOperationContext context) 150 { 151 bool success = false; 152 bool setCloseHandle = false; 153 context = null; 154 155 lock (this.thisLock) 156 { 157 foreach (AsyncOperationContext value in this.activeOperations.Values) 158 { 159 if (object.Equals(value.UserState, userState)) 160 { 161 if (success) 162 { 163 success = false; 164 break; 165 } 166 else 167 { 168 context = value; 169 success = true; 170 } 171 } 172 } 173 174 if (success) 175 { 176 this.activeOperations.Remove(context.OperationId); 177 setCloseHandle = (this.closeHandle != null) && (this.activeOperations.Count == 0); 178 } 179 } 180 181 if (setCloseHandle) 182 { 183 this.closeHandle.Set(); 184 } 185 186 return success; 187 } 188 Close(TimeSpan timeout)189 public void Close(TimeSpan timeout) 190 { 191 InitializeCloseHandle(); 192 if (!this.closeHandle.Wait(timeout)) 193 { 194 throw FxTrace.Exception.AsError(new TimeoutException(SR2.TimeoutOnOperation(timeout))); 195 } 196 } 197 BeginClose(TimeSpan timeout, AsyncCallback callback, object state)198 public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state) 199 { 200 InitializeCloseHandle(); 201 return new CloseAsyncResult(this.closeHandle, timeout, callback, state); 202 } 203 EndClose(IAsyncResult result)204 public void EndClose(IAsyncResult result) 205 { 206 CloseAsyncResult.End(result); 207 } 208 InitializeCloseHandle()209 void InitializeCloseHandle() 210 { 211 bool setCloseHandle = false; 212 lock (this.thisLock) 213 { 214 this.closeHandle = new AsyncWaitHandle(EventResetMode.ManualReset); 215 setCloseHandle = (this.activeOperations.Count == 0); 216 217 if (this.IsAborted) 218 { 219 setCloseHandle = true; 220 } 221 } 222 if (setCloseHandle) 223 { 224 this.closeHandle.Set(); 225 } 226 } 227 228 class CloseAsyncResult : AsyncResult 229 { 230 static Action<object, TimeoutException> onWaitCompleted = new Action<object, TimeoutException>(OnWaitCompleted); 231 AsyncWaitHandle asyncWaitHandle; 232 CloseAsyncResult(AsyncWaitHandle asyncWaitHandle, TimeSpan timeout, AsyncCallback callback, object state)233 internal CloseAsyncResult(AsyncWaitHandle asyncWaitHandle, TimeSpan timeout, AsyncCallback callback, object state) 234 : base(callback, state) 235 { 236 this.asyncWaitHandle = asyncWaitHandle; 237 if (this.asyncWaitHandle.WaitAsync(onWaitCompleted, this, timeout)) 238 { 239 Complete(true); 240 } 241 } 242 OnWaitCompleted(object state, TimeoutException asyncException)243 static void OnWaitCompleted(object state, TimeoutException asyncException) 244 { 245 CloseAsyncResult thisPtr = (CloseAsyncResult)state; 246 thisPtr.Complete(false, asyncException); 247 } 248 End(IAsyncResult result)249 internal static void End(IAsyncResult result) 250 { 251 AsyncResult.End<CloseAsyncResult>(result); 252 } 253 } 254 } 255 } 256