// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Extensions; public static class WaitHandleExtensions { // http://stackoverflow.com/questions/25382583/waiting-on-a-named-semaphore-with-waitone100-vs-waitone0-task-delay100 // http://blog.nerdbank.net/2011/07/c-await-for-waithandle.html // F# has a AwaitWaitHandle method that accepts a time out... and seems pretty complex... // version below should be OK public static Task WaitOneAsync(this WaitHandle handle, int millisecondsTimeout = Timeout.Infinite) { var tcs = new TaskCompletionSource(); var callbackHandleInitLock = new Lock(); lock (callbackHandleInitLock) { RegisteredWaitHandle? callbackHandle = null; // ReSharper disable once RedundantAssignment callbackHandle = ThreadPool.RegisterWaitForSingleObject( handle, (state, timedOut) => { // TODO: We aren't checking if this is timed out tcs.SetResult(null); // we take a lock here to make sure the outer method has completed setting the local variable callbackHandle. lock (callbackHandleInitLock) { // ReSharper disable once PossibleNullReferenceException // ReSharper disable once AccessToModifiedClosure callbackHandle?.Unregister(null); } }, /*state:*/ null, /*millisecondsTimeOutInterval:*/ millisecondsTimeout, /*executeOnlyOnce:*/ true); } return tcs.Task; } }