/// <summary> /// Ensures that two locks are mutually exclusive by trying to acquire one lock (on another thread) while the other lock is held /// and waiting the specified amount of time /// </summary> private void TestMutuallyExclusive <TLock1, TLock2>(Func <TLock1> lockCreator1, Func <TLock2> lockCreator2, int waitTimeInMilliseconds = 500, bool assertExclusive = true) where TLock1 : IDisposable where TLock2 : IDisposable { // Try with first lock held TestMutuallyExclusiveHelper(lockCreator1, lockCreator2, 1, 2, waitTimeInMilliseconds, assertExclusive); // Now try with second lock held TestMutuallyExclusiveHelper(lockCreator2, lockCreator1, 2, 1, waitTimeInMilliseconds, assertExclusive); if (assertExclusive) { Task lockCreator1StartedEvent; Task lockCreator2StartedEvent; TaskSourceSlim <int[]> accessCheckTaskProvider = TaskSourceSlim.Create <int[]>(); var loop1Completion = TryAcquireLoop(lockCreator1, accessCheckTaskProvider.Task, out lockCreator1StartedEvent); var loop2Completion = TryAcquireLoop(lockCreator2, accessCheckTaskProvider.Task, out lockCreator2StartedEvent); // Wait for task bodies to be entered lockCreator1StartedEvent.Wait(); lockCreator2StartedEvent.Wait(); // Start the loops and provide the access check array accessCheckTaskProvider.SetResult(new int[1]); // Wait for the loops to complete loop1Completion.GetAwaiter().GetResult(); loop2Completion.GetAwaiter().GetResult(); } }
public async Task SetFinalResult() { var taskResult = await BatchExecutionTask; // "Yielding" execution to another thread to avoid deadlocks. // SetResult causes a task's continuation to run in the same thread that can cause issues // because a continuation of BatchExecutionTask could be a synchronous continuation as well. await Task.Yield(); FinalTaskResult.SetResult(taskResult); }
/// <summary> /// Marks the action block as completed. /// </summary> public void Complete() { bool schedulingCompleted = Volatile.Read(ref m_schedulingCompleted); if (schedulingCompleted) { return; } Volatile.Write(ref m_schedulingCompleted, true); // Release one thread that will release all the threads when all the elements are processed. m_semaphore.Release(); m_schedulingCompletedTcs.SetResult(null); }
private async Task ProcessQueueItem(string logPrefix) { // ReSharper disable once UnusedVariable bool itemDequeued = _backgroundTaskQueue.TryDequeue(out var queueItem); Contract.Assert(itemDequeued); if (queueItem.SyncTask.IsValid) { _tracer.Diagnostic(_context, $"{logPrefix} received SyncTask {queueItem.SyncTask.Task.Id} ({queueItem.Tag})"); // Avoid getting blocked by ending up in a blocking wait. This can happen because TaskCompletionSource // SetResult runs on the active thread and can unblock other waiting tasks and resume their async // calls. Once such case, with multiple interacting BackgroundThreadTracker objects, causes the active // thread to end up in the blocking GetConsumingEnumerable() of another instance. So, set the result // in another thread and move on here immediately. The task created here is not tracked. TaskSourceSlim <ValueUnit> tcs = queueItem.SyncTask; tcs.SetResult(ValueUnit.Void); } else { Contract.Assert(queueItem.Task != null); try { if (_logTasks) { _tracer.Diagnostic(_context, $"{logPrefix} await task {queueItem.Task.Id} ({queueItem.Tag})"); } await queueItem.Task; if (_logTasks) { _tracer.Diagnostic(_context, $"{logPrefix} await task {queueItem.Task.Id} ({queueItem.Tag}) complete"); } } catch (Exception exception) { _tracer.Debug(_context, $"{logPrefix} ignoring exception in task {queueItem.Task.Id}: {exception}"); } } }
/// <summary> /// Ensures that two locks are mutually exclusive by trying to acquire one lock (on another thread) while the other lock is held /// and waiting the specified amount of time /// </summary> private void TestMutuallyExclusiveHelper <TLock1, TLock2>(Func <TLock1> lockCreator1, Func <TLock2> lockCreator2, int lockNumber1, int lockNumber2, int waitTimeInMilliseconds, bool assertExclusive) where TLock1 : IDisposable where TLock2 : IDisposable { TaskSourceSlim <bool> lockCreator2ExecutingEvent = TaskSourceSlim.Create <bool>(); bool[] lock2Entered = new bool[1]; Task lockCreator2CompletionTask; using (lockCreator1()) { lockCreator2CompletionTask = Task.Run(() => { lockCreator2ExecutingEvent.SetResult(true); using (lockCreator2()) { } lock2Entered[0] = true; }); // Wait for the task to start executing first so the next wait timeout // doesn't vary depending on when the task scheduler decides to execute the task lockCreator2ExecutingEvent.Task.Wait(); if (assertExclusive) { XAssert.IsFalse(lockCreator2CompletionTask.Wait(waitTimeInMilliseconds), string.Format(CultureInfo.InvariantCulture, "SHOULD NOT be able to enter lock {0} while lock {1} is held", lockNumber1, lockNumber2)); } else { XAssert.IsTrue(lockCreator2CompletionTask.Wait(waitTimeInMilliseconds), string.Format(CultureInfo.InvariantCulture, "SHOULD be able to enter lock {0} while lock {1} is held", lockNumber1, lockNumber2)); } } XAssert.IsTrue(lockCreator2CompletionTask.Wait(waitTimeInMilliseconds) || lock2Entered[0], "Should be able to enter lock 2 after lock 1 is released"); }
/// <summary> /// Attempts to acquire lock in a tight loop ensuring that it has exclusive access to an arrays /// </summary> private Task TryAcquireLoop <TLock>(Func <TLock> lockCreator, Task <int[]> accessCheckTask, out Task startedEvent) where TLock : IDisposable { TaskSourceSlim <bool> startedEventCompletion = TaskSourceSlim.Create <bool>(); startedEvent = startedEventCompletion.Task; return(Task.Run(() => { startedEventCompletion.SetResult(true); // Wait on this task to ensure the loops start around the same time int[] accessCheck = accessCheckTask.Result; for (int i = 0; i < 10000; i++) { using (lockCreator()) { // Each operation should succeed with the anticipated value // if we have exclusive access XAssert.AreEqual(1, Interlocked.Increment(ref accessCheck[0])); XAssert.AreEqual(0, Interlocked.Decrement(ref accessCheck[0])); } } })); }
public async Task TestHistoricMetadataPathStringRoundtrip() { LoggingContext loggingContext = CreateLoggingContextForTest(); PipExecutionContext context; HistoricMetadataCache cache = null; var hmcFolderName = "hmc"; for (int i = 0; i < 3; i++) { CreateHistoricCache(loggingContext, hmcFolderName, out context, out cache, out var memoryArtifactCache); var process1 = SchedulerTest.CreateDummyProcess(context, new PipId(1)); var process2 = SchedulerTest.CreateDummyProcess(context, new PipId(2)); var pathTable = context.PathTable; // Add some random paths to ensure path table indices are different after loading AbsolutePath.Create(pathTable, X("/H/aslj/sfas/832.stxt")); AbsolutePath.Create(pathTable, X("/R/f/s/Historic")); AbsolutePath.Create(pathTable, X("/M/hgf/sf4as/83afsd")); AbsolutePath.Create(pathTable, X("/Z/bd/sfas/Cache")); var abPath1 = AbsolutePath.Create(pathTable, X("/H/aslj/sfas/p1OUT.bin")); var abPath2 = AbsolutePath.Create(pathTable, X("/H/aslj/sfas/P2.txt")); var pathSet1 = ObservedPathSetTestUtilities.CreatePathSet( pathTable, X("/X/a/b/c"), X("/X/d/e"), X("/X/a/b/c/d")); PipCacheDescriptorV2Metadata metadata1 = new PipCacheDescriptorV2Metadata { StaticOutputHashes = new List <AbsolutePathFileMaterializationInfo> { new AbsolutePathFileMaterializationInfo { AbsolutePath = abPath1.GetName(pathTable).ToString(context.StringTable), Info = new BondFileMaterializationInfo { FileName = "p1OUT.bin" } } } }; var storedPathSet1 = await cache.TryStorePathSetAsync(pathSet1, preservePathCasing : false); var storedMetadata1 = await cache.TryStoreMetadataAsync(metadata1); var weakFingerprint1 = new WeakContentFingerprint(FingerprintUtilities.CreateRandom()); var strongFingerprint1 = new StrongContentFingerprint(FingerprintUtilities.CreateRandom()); var cacheEntry = new CacheEntry(storedMetadata1.Result, nameof(HistoricMetadataCacheTests), ArrayView <ContentHash> .Empty); var publishedCacheEntry = await cache.TryPublishCacheEntryAsync(process1, weakFingerprint1, storedPathSet1.Result, strongFingerprint1, cacheEntry); var pathSet2 = ObservedPathSetTestUtilities.CreatePathSet( pathTable, X("/F/a/y/c"), X("/B/d/e"), X("/G/a/z/c/d"), X("/B/a/b/c")); PipCacheDescriptorV2Metadata metadata2 = new PipCacheDescriptorV2Metadata { StaticOutputHashes = new List <AbsolutePathFileMaterializationInfo> { new AbsolutePathFileMaterializationInfo { AbsolutePath = abPath2.ToString(pathTable), Info = new BondFileMaterializationInfo { FileName = abPath2.GetName(pathTable).ToString(context.StringTable) } } }, DynamicOutputs = new List <List <RelativePathFileMaterializationInfo> > { new List <RelativePathFileMaterializationInfo> { new RelativePathFileMaterializationInfo { RelativePath = @"dir\P2Dynamic.txt", Info = new BondFileMaterializationInfo { FileName = "p2dynamic.txt" } }, new RelativePathFileMaterializationInfo { RelativePath = @"dir\P2dynout2.txt", Info = new BondFileMaterializationInfo { FileName = null } } } } }; var storedPathSet2 = await cache.TryStorePathSetAsync(pathSet2, preservePathCasing : false); var storedMetadata2 = await cache.TryStoreMetadataAsync(metadata2); var cacheEntry2 = new CacheEntry(storedMetadata2.Result, nameof(HistoricMetadataCacheTests), ArrayView <ContentHash> .Empty); var strongFingerprint2 = new StrongContentFingerprint(FingerprintUtilities.CreateRandom()); var publishedCacheEntry2 = await cache.TryPublishCacheEntryAsync(process1, weakFingerprint1, storedPathSet2.Result, strongFingerprint2, cacheEntry2); await cache.CloseAsync(); memoryArtifactCache.Clear(); PipExecutionContext loadedContext; HistoricMetadataCache loadedCache; TaskSourceSlim <bool> loadCompletionSource = TaskSourceSlim.Create <bool>(); TaskSourceSlim <bool> loadCalled = TaskSourceSlim.Create <bool>(); BoxRef <bool> calledLoad = new BoxRef <bool>(); CreateHistoricCache(loggingContext, "hmc", out loadedContext, out loadedCache, out memoryArtifactCache, loadTask: async hmc => { loadCalled.SetResult(true); await loadCompletionSource.Task; }); var operationContext = OperationContext.CreateUntracked(loggingContext); var retrievePathSet1Task = loadedCache.TryRetrievePathSetAsync(operationContext, WeakContentFingerprint.Zero, storedPathSet1.Result); var retrievdMetadata1Task = loadedCache.TryRetrieveMetadataAsync( process1, WeakContentFingerprint.Zero, StrongContentFingerprint.Zero, storedMetadata1.Result, storedPathSet1.Result); var getCacheEntry1Task = loadedCache.TryGetCacheEntryAsync( process1, weakFingerprint1, storedPathSet1.Result, strongFingerprint1); Assert.False(retrievePathSet1Task.IsCompleted, "Before load task completes. TryRetrievePathSetAsync operations should block"); Assert.False(retrievdMetadata1Task.IsCompleted, "Before load task completes. TryRetrieveMetadataAsync operations should block"); Assert.False(getCacheEntry1Task.IsCompleted, "Before load task completes. TryGetCacheEntryAsync operations should block"); Assert.True(loadCalled.Task.Wait(TimeSpan.FromSeconds(10)) && loadCalled.Task.Result, "Load should have been called in as a result of querying"); loadCompletionSource.SetResult(true); var maybeLoadedPathSet1 = await retrievePathSet1Task; var maybeLoadedMetadata1 = await retrievdMetadata1Task; var maybeLoadedCacheEntry1 = await getCacheEntry1Task; Assert.Equal(storedMetadata1.Result, maybeLoadedCacheEntry1.Result.Value.MetadataHash); var maybeLoadedPathSet2 = await loadedCache.TryRetrievePathSetAsync(operationContext, WeakContentFingerprint.Zero, storedPathSet2.Result); var maybeLoadedMetadata2 = await loadedCache.TryRetrieveMetadataAsync( process2, WeakContentFingerprint.Zero, StrongContentFingerprint.Zero, storedMetadata2.Result, storedPathSet2.Result); AssertPathSetEquals(pathTable, pathSet1, loadedContext.PathTable, maybeLoadedPathSet1.Result); AssertPathSetEquals(pathTable, pathSet2, loadedContext.PathTable, maybeLoadedPathSet2.Result); AssertMetadataEquals(metadata1, maybeLoadedMetadata1.Result); AssertMetadataEquals(metadata2, maybeLoadedMetadata2.Result); await loadedCache.CloseAsync(); } }
private void SetResult(SandboxedProcessResult result) { Contract.Requires(m_detouredProcess != null); m_resultTaskCompletionSource.SetResult(result); }
/// <summary> /// Signals the Request as being complete with the given success value. /// </summary> /// <param name="completeSuccessfully">Whether the request was successfully satisfied.</param> public void Complete(bool completeSuccessfully) { _tcs.SetResult(completeSuccessfully); }
/// <nodoc /> public virtual void Success() => _taskSource.SetResult(BoolResult.Success);
/// <nodoc /> private void RequestStop() { Logger.Info("Received request to stop"); m_shutdownTask.SetResult(Unit.Void); }