示例#1
0
        /// <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();
            }
        }
示例#2
0
            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);
            }
示例#3
0
        /// <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);
        }
示例#4
0
        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}");
                }
            }
        }
示例#5
0
        /// <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");
        }
示例#6
0
        /// <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]));
                    }
                }
            }));
        }
示例#7
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();
            }
        }
示例#8
0
        private void SetResult(SandboxedProcessResult result)
        {
            Contract.Requires(m_detouredProcess != null);

            m_resultTaskCompletionSource.SetResult(result);
        }
示例#9
0
 /// <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);
 }
示例#10
0
 /// <nodoc />
 public virtual void Success() => _taskSource.SetResult(BoolResult.Success);
示例#11
0
 /// <nodoc />
 private void RequestStop()
 {
     Logger.Info("Received request to stop");
     m_shutdownTask.SetResult(Unit.Void);
 }