Пример #1
0
        public Task PurgeIsCanceledForShutdown()
        {
            var tcsBlockEnumeration = TaskSourceSlim.Create <bool>();

            return(FillSoNextPutTriggersSoftPurgeThenRunTest(
                       async list =>
            {
                Output.WriteLine("Awaiting tsc...");
                await tcsBlockEnumeration.Task;
                Output.WriteLine("Tsc is done");
                return list;
            },
                       async(store, hash1, hash2, stream) =>
            {
                var hash = await PutAsync(store, stream);

                Task shutdownTask = Task.Run(() => store.ShutdownAsync(Context));

                while (!store.ShutdownStarted)
                {
                    await Task.Yield();
                }

                tcsBlockEnumeration.SetResult(true);

                await shutdownTask;

                Assert.True(FileSystem.FileExists(store.GetReplicaPathForTest(hash1, 0)));
                Assert.True(FileSystem.FileExists(store.GetReplicaPathForTest(hash2, 0)));
                Assert.True(FileSystem.FileExists(store.GetReplicaPathForTest(hash, 0)));
            }));
        }
Пример #2
0
        /// <summary>
        /// Constructor
        /// </summary>
        public RemoteWorker(
            bool isGrpcEnabled,
            LoggingContext appLoggingContext,
            uint workerId,
            MasterService masterService,
            ServiceLocation serviceLocation)
            : base(workerId, name: I($"#{workerId} ({serviceLocation.IpAddress}::{serviceLocation.Port})"))
        {
            m_isGrpcEnabled           = isGrpcEnabled;
            m_appLoggingContext       = appLoggingContext;
            m_masterService           = masterService;
            m_buildRequests           = new BlockingCollection <ValueTuple <PipCompletionTask, SinglePipBuildRequest> >();
            m_attachCompletion        = TaskSourceSlim.Create <bool>();
            m_executionBlobCompletion = TaskSourceSlim.Create <bool>();

            m_serviceLocation = serviceLocation;

            if (isGrpcEnabled)
            {
                m_workerClient = new Grpc.GrpcWorkerClient(m_appLoggingContext, masterService.DistributionServices.BuildId, serviceLocation.IpAddress, serviceLocation.Port);
            }
            else
            {
#if !DISABLE_FEATURE_BOND_RPC
                m_workerClient = new InternalBond.BondWorkerClient(m_appLoggingContext, Name, serviceLocation.IpAddress, serviceLocation.Port, masterService.DistributionServices, OnActivateConnection, OnDeactivateConnection, OnConnectionTimeOut);
#endif
            }

            // Depending on how long send requests take. It might make sense to use the same thread between all workers.
            m_sendThread = new Thread(SendBuildRequests);
        }
Пример #3
0
        /// <summary>
        /// Returns a task representing the result of the given task which will run continuations asynchronously.
        /// </summary>
        public static Task <T> RunContinuationsAsync <T>(this Task <T> task)
        {
            var taskSource = TaskSourceSlim.Create <T>();

            taskSource.LinkToTask(task);
            return(taskSource.Task);
        }
Пример #4
0
        /// <summary>
        /// Class constructor
        /// </summary>
        /// <param name="appLoggingContext">Application-level logging context</param>
        /// <param name="maxProcesses">the maximum number of concurrent pips on the worker</param>
        /// <param name="config">Distribution config</param>\
        /// <param name="buildId">the build id</param>
        public WorkerService(LoggingContext appLoggingContext, int maxProcesses, IDistributionConfiguration config, string buildId)
        {
            m_isGrpcEnabled = config.IsGrpcEnabled;

            m_appLoggingContext = appLoggingContext;
            m_maxProcesses      = maxProcesses;
            m_port     = config.BuildServicePort;
            m_services = new DistributionServices(buildId);
            if (m_isGrpcEnabled)
            {
                m_workerServer = new Grpc.GrpcWorkerServer(this, appLoggingContext, buildId);
            }
            else
            {
#if !DISABLE_FEATURE_BOND_RPC
                m_bondWorkerService = new InternalBond.BondWorkerServer(appLoggingContext, this, m_port, m_services);
                m_workerServer      = m_bondWorkerService;
#endif
            }

            m_attachCompletionSource    = TaskSourceSlim.Create <bool>();
            m_exitCompletionSource      = TaskSourceSlim.Create <bool>();
            m_workerRunnablePipObserver = new WorkerRunnablePipObserver(this);
            m_sendThread = new Thread(SendBuildResults);
        }
Пример #5
0
 public QueueItem(TaskSourceSlim <ValueUnit> syncTask, string tag)
     : this()
 {
     Task     = null;
     SyncTask = syncTask;
     Tag      = tag;
 }
Пример #6
0
        /// <inheritdoc />
        public IEnumerable <Task <Possible <StrongFingerprint, Failure> > > EnumerateStrongFingerprints(
            WeakFingerprintHash weak, UrgencyHint urgencyHint, Guid activityId)
        {
            // TODO: Extend IAsyncEnumerable up through EnumerateStrongFingerprints
            var tcs = TaskSourceSlim.Create <IEnumerable <GetSelectorResult> >();

            yield return(Task.Run(
                             async() =>
            {
                try
                {
                    var results = await ReadOnlyCacheSession.GetSelectors(new Context(Logger), weak.ToMemoization(), CancellationToken.None).ToList();
                    tcs.SetResult(results);
                    return results.Any() ? results.First().FromMemoization(weak, CacheId) : StrongFingerprintSentinel.Instance;
                }
                catch (Exception ex)
                {
                    tcs.SetException(ex);
                    throw;
                }
            }));

            // For now, callers should always await the first task before enumerating the rest
            Contract.Assert(tcs.Task.IsCompleted);
            IEnumerable <GetSelectorResult> otherResults = tcs.Task.GetAwaiter().GetResult();

            foreach (var otherResult in otherResults.Skip(1))
            {
                yield return(Task.FromResult(otherResult.FromMemoization(weak, CacheId)));
            }
        }
Пример #7
0
        internal override void FeedStdErr(SandboxedProcessOutputBuilder builder, TaskSourceSlim <Unit> tsc, string line)
        {
            if (line == null) // designates EOF
            {
                // extract cpu times from the last recorder line (which should be the output of /usr/bin/time)
                m_cpuTimes = ExtractCpuTimes(m_lastStdErrLine, out string unprocessedFragment);

                // feed whatever wasn't consumed
                FeedOutputBuilder(builder, tsc, unprocessedFragment);

                // feed EOF
                FeedOutputBuilder(builder, tsc, null);
            }
            else
            {
                // feed previous line (if any)
                if (m_lastStdErrLine != null)
                {
                    FeedOutputBuilder(builder, tsc, m_lastStdErrLine);
                }

                // update previous line
                m_lastStdErrLine = line;
            }
        }
Пример #8
0
 public PipCompletionTask(OperationContext operationContext, RunnablePip pip)
 {
     RunnablePip      = pip;
     OperationContext = operationContext;
     Completion       = TaskSourceSlim.Create <Lazy <ExecutionResult> >();
     QueuedTime       = DateTime.UtcNow;
 }
Пример #9
0
        /// <summary>
        /// Class constructor
        /// </summary>
        /// <param name="client">the bond tcp client used to create the proxy</param>
        /// <param name="createProxyCallback">callback used to create a bond proxy</param>
        /// <param name="loggingContext">the logging context</param>
        /// <param name="services">shared services for distribution</param>
        /// <param name="maxConnectionConcurrency">the maximum number of connections</param>
        public BondProxyConnectionManager(
            BondTcpClient <TProxy> client,
            BondTcpClient <TProxy> .CreateProxyCallback createProxyCallback,
            LoggingContext loggingContext,
            DistributionServices services,
            int maxConnectionConcurrency = 1)
        {
            m_client = client;
            m_createProxyCallback      = createProxyCallback;
            m_loggingContext           = loggingContext;
            m_maxConnectionConcurrency = maxConnectionConcurrency;
            m_services      = services;
            m_bufferManager = services.BufferManager;

            m_proxySemaphore = new NullSemaphore();

            // m_proxySemaphore = new SemaphoreSlim(m_maxConnectionConcurrency);
            m_stopwatch      = Stopwatch.StartNew();
            m_heartbeatTimer = new Timer(HeartbeatTimerCallback);
            m_connections    = new TrackedConnection[m_maxConnectionConcurrency];
            for (int i = 0; i < m_maxConnectionConcurrency; i++)
            {
                m_connections[i] = new TrackedConnection(this);
            }

            m_isActiveCompletionSource = TaskSourceSlim.Create <bool>();
        }
Пример #10
0
        private void DeactivateConnection(TrackedConnection connection)
        {
            lock (m_syncLock)
            {
                if (m_isActiveCompletionSource.Task.IsCompleted)
                {
                    if (m_isActiveCompletionSource.Task.Result)
                    {
                        m_isActiveCompletionSource = TaskSourceSlim.Create <bool>();
                    }
                }

                if (m_exceededInactivityTimeout)
                {
                    m_isActiveCompletionSource.TrySetResult(false);
                }
            }

            OnDeactivateConnection?.Invoke(this, EventArgs.Empty);

            // TODO: Do nothing to actual connection for now.
            // Consider recycling connection (ie create new BondTcpConnection) if
            // connection fails too many times or hasn't had a successful call for a significant
            // interval.
            // NOTE: connection may be null
            Analysis.IgnoreArgument(connection);
        }
Пример #11
0
        public async Task NoAddsOnceStopping()
        {
            var context = new Context(Logger);

            using (var runner = CreateBackgroundTaskTracker())
            {
                var completion = TaskSourceSlim.Create <int>();

                runner.Add(completion.Task);

                Task stopTask = runner.ShutdownAsync(context);

                Exception exception = null;
                try
                {
                    runner.Add(Task.FromResult(0));
                }
                catch (Exception caughtException)
                {
                    Assert.True(runner.InShutdown);
                    exception = caughtException;
                }

                Assert.NotNull(exception);

                Task.Run(() => completion.SetResult(0)).Should().NotBeNull();

                await stopTask;
            }
        }
Пример #12
0
 internal AddFileItem(IDropItem item)
 {
     TaskSource = TaskSourceSlim.Create <AddFileResult>();
     m_dropItem = item;
     m_fileBlobDescriptorForUpload    = null;
     m_fileBlobDescriptorForAssociate = null;
 }
Пример #13
0
        /// <inheritdoc />
        public Task <IIpcResult> Send(IIpcOperation operation)
        {
            Contract.Requires(operation != null);

            var request = new Request(operation);

            // Must add the request to the m_pendingRequest dictionary before posting it to m_sendRequestBlock
            // Otherwise, the following can happen:
            //   1) the request is posted
            //   2) the request is picked up from the queue and processed
            //   3) the request handler looks up corresponding completionSource in the dictionary which is not there yet (ERROR)
            //   4) the TaskCompletionSource is added to the dictionary
            var completionSource = TaskSourceSlim.Create <IIpcResult>();

            m_pendingRequests[request.Id] = completionSource;

            operation.Timestamp.Request_BeforePostTime = DateTime.UtcNow;
            bool posted = m_sendRequestBlock.Post(request);

            if (!posted)
            {
                // if the request was not posted:
                // (1) remove it from the dictionary
                TaskSourceSlim <IIpcResult> src;
                m_pendingRequests.TryRemove(request.Id, out src);

                // (2) complete it (with TransmissionError)
                completionSource.TrySetResult(new IpcResult(
                                                  IpcResultStatus.TransmissionError,
                                                  "Could not post IPC request: the client has already terminated."));
            }

            return(completionSource.Task);
        }
Пример #14
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();
            }
        }
Пример #15
0
 public QueueItem(Task task, string tag)
     : this()
 {
     Task     = task;
     SyncTask = default;
     Tag      = tag;
 }
Пример #16
0
        public async Task IncreaseConcurrency()
        {
            int count = 0;

            var waitForFirstTwoItems = TaskSourceSlim.Create <object>();
            // Event that will hold first two workers.
            var mre         = new ManualResetEventSlim(false);
            var actionBlock = new ActionBlockSlim <int>(
                2,
                n =>
            {
                var currentCount = Interlocked.Increment(ref count);
                if (currentCount == 2)
                {
                    // Notify the test that 2 items are processed.
                    waitForFirstTwoItems.SetResult(null);
                }

                if (currentCount <= 2)
                {
                    // This is the first or the second thread that should be blocked before we increase the number of threads.
                    mre.Wait(TimeSpan.FromSeconds(100));
                }

                Thread.Sleep(1);
            });

            // Schedule work
            actionBlock.Post(1);
            actionBlock.Post(2);

            await waitForFirstTwoItems.Task;

            // The first 2 threads should be blocked in the callback in the action block,
            // but the count should be incremented
            Assert.Equal(2, count);

            var task = actionBlock.CompletionAsync();

            // The task should not be completed yet!
            Assert.NotEqual(TaskStatus.RanToCompletion, task.Status);

            // This will cause another thread to spawn
            actionBlock.IncreaseConcurrencyTo(3);

            // Add more work
            actionBlock.Post(3);

            actionBlock.Complete();

            // Release the first 2 threads
            mre.Set();

            // Waiting for completion
            await task;

            // The new thread should run and increment the count
            Assert.Equal(3, count);
        }
Пример #17
0
        /// <summary>
        ///     Waits for all currently added background tasks to complete.
        /// </summary>
        public Task Synchronize(string tag = null)
        {
            var syncCompletion = TaskSourceSlim.Create <ValueUnit>();

            Enqueue(new QueueItem(syncCompletion, tag), "Synchronize", syncCompletion.Task.Id, tag);

            return(syncCompletion.Task);
        }
Пример #18
0
 internal AddFileItem(IDropItem item)
 {
     DropResultTaskSource             = TaskSourceSlim.Create <AddFileResult>();
     m_dropItem                       = item;
     m_fileBlobDescriptorForUpload    = null;
     m_fileBlobDescriptorForAssociate = null;
     BuildManifestTaskSource          = TaskSourceSlim.Create <RegisterFileForBuildManifestResult>();
 }
Пример #19
0
 private LockHandle(LockHandle lockHandle, TimeSpan lockAcquisitionDuration)
 {
     _locks = lockHandle._locks;
     TaskCompletionSource = lockHandle.TaskCompletionSource;
     Key       = lockHandle.Key;
     _handleId = lockHandle._handleId;
     LockAcquisitionDuration = lockAcquisitionDuration;
 }
Пример #20
0
 private static void FeedOutputBuilder(SandboxedProcessOutputBuilder output, TaskSourceSlim <Unit> signalCompletion, string line)
 {
     output.AppendLine(line);
     if (line == null)
     {
         signalCompletion.TrySetResult(Unit.Void);
     }
 }
Пример #21
0
        /// <nodoc />
        public MultiplexingClient(IClientConfig config, Stream stream)
        {
            Contract.Requires(config != null);
            Contract.Requires(stream != null);

            Config   = config;
            Logger   = config.Logger ?? VoidLogger.Instance;
            m_stream = stream;

            m_pendingRequests             = new ConcurrentDictionary <int, TaskSourceSlim <IIpcResult> >();
            m_disconnectRequestedByServer = false;

            // Receiving Dataflow:
            //   This generic server will call 'SetResponse' for every received Response.  'SetResponse'
            //   could be done in parallel, but there is no point, since they all access a shared concurrent
            //   dictionary and all they do is lookup task completion source and set a result for it.
            m_responseListener = new GenericServer <Response>(
                name: "MultiplexingClient.ResponseListener",
                config: new ServerConfig {
                Logger = Logger, MaxConcurrentClients = 1
            },
                listener: ReceiveResponseAsync,
                clientFailuresAreFatal: true);

            // Sending Dataflow:
            //   All 'Send' requests are concurrently queued up here. Processing of this block
            //   ('SendRequestAsync') must be sequential, because uses the shared connection.
            m_sendRequestBlock = new ActionBlock <Request>(
                SendRequestAsync,
                new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = 1,
            });

            // set continuations that handle errors (unblock pending requests and set failure as completion of this client)
            var continuationDone = TaskSourceSlim.Create <Unit>();

            m_responseListener.Completion.ContinueWith(_ => m_sendRequestBlock.Complete());
            m_sendRequestBlock.Completion.ContinueWith(async _ =>
            {
                m_responseListener.Complete();

                UnblockPendingRequests(new IpcResult(IpcResultStatus.GenericError, "MultiplexingClient completed before all requests were handled"));
                if (!m_disconnectRequestedByServer)
                {
                    var succeeded = await Request.StopRequest.TrySerializeAsync(m_stream);
                    Logger.Verbose("Sending StopRequest {0}.", succeeded ? "Succeeded" : "Failed");
                }

                continuationDone.SetResult(Unit.Void);
            });

            // start listening for responses
            m_responseListener.Start(SetResponseAsync);

            // set the completion task
            m_completion = TaskUtilities.SafeWhenAll(new[] { m_sendRequestBlock.Completion, m_responseListener.Completion, continuationDone.Task });
        }
Пример #22
0
        /// <summary>
        /// Waits until all processes have terminated.
        /// </summary>
        /// <remarks>
        /// This function may safely be invoked concurrently / multiple times.
        /// </remarks>
        /// <returns>Boolean indicating whether all processes have terminated (false indicates that a timeout occurred instead)</returns>
        public Task <bool> WaitAsync(TimeSpan timeout)
        {
            Contract.Requires(timeout >= TimeSpan.Zero);
            Contract.Requires(timeout.TotalMilliseconds < uint.MaxValue);

            ManualResetEvent doneEvent;

            lock (m_lock)
            {
                Contract.Assume(!m_disposed, "WaitAsync called on a disposed JobObject");

                doneEvent = m_doneEvent;

                if (m_done || !HasAnyProcesses())
                {
                    // Fast path: no need to wait
                    // Note that we check HasAnyProcesses() in addition to m_done so as to more likely avoid pathological behavior in which calls to WaitAsync
                    // happen close to job exit (e.g. because the job had one process, and the process handle already signalled); in that case we are
                    // racing with the completion port drainer to set m_done, so creating an event and possibly sleeping the current thread would be wasteful.
                    return(BoolTask.True);
                }
                else if (doneEvent == null)
                {
                    // Slower path: need to wait as the first waiter (no event yet).
                    doneEvent = m_doneEvent = new ManualResetEvent(initialState: false);
                }
                else
                {
                    // Slower path: need to wait on an existing event (with a previous waiter).
                }
            }

            Contract.Assert(doneEvent != null);

            // doneEvent is now an event that was (at one point) m_doneEvent.
            // It may be set already, but RegisterWaitForSingleObject is robust to that case.
            var waiter = TaskSourceSlim.Create <bool>();
            RegisteredWaitHandle waitPoolHandle = null;

            waitPoolHandle = ThreadPool.RegisterWaitForSingleObject(
                doneEvent,
                (state, timedOut) =>
            {
                waiter.SetResult(!timedOut);

                // Note that the assignment of waitPoolHandle races with the callback.
                // Worst case, we'll let the garbage collector get it.
                if (waitPoolHandle != null)
                {
                    waitPoolHandle.Unregister(null);
                }
            },
                state: null,
                timeout: timeout,
                executeOnlyOnce: true);

            return(waiter.Task);
        }
Пример #23
0
 /// <nodoc />
 public PluginManager(LoggingContext loggingContext, string logDirectory, IEnumerable <string> pluginLocations)
 {
     m_plugins        = new ConcurrentDictionary <string, Task <Possible <IPlugin> > >();
     m_pluginHandlers = new PluginHandlers();
     m_pluginStopTask = TaskSourceSlim.Create <Unit>();
     m_loggingContext = loggingContext;
     m_logDirectory   = logDirectory;
     m_pluginPaths    = pluginLocations.ToList();
 }
Пример #24
0
        /// <nodoc/>
        public ListenerSourceBlock(CancellableListener listener, string name = "unknown", IIpcLogger logger = null)
        {
            Contract.Requires(listener != null);

            m_logger       = logger ?? VoidLogger.Instance;
            m_name         = name ?? "ListenerSourceBlock";
            m_listener     = listener;
            m_stopTask     = TaskSourceSlim.Create <Unit>();
            m_startCounter = 0;
        }
Пример #25
0
            /// <summary>
            /// Initializes a new instance of the <see cref="LockHandle" /> struct for the given collection/key.
            /// </summary>
            public LockHandle(LockSet <TKey> locks, TKey key)
            {
                Contract.Requires(locks != null);
                Contract.Requires(key != null);

                TaskCompletionSource = TaskSourceSlim.Create <ValueUnit>();
                _locks    = locks;
                Key       = key;
                _handleId = Interlocked.Increment(ref _currentHandleId);
            }
Пример #26
0
        public async Task <BondTcpConnection <TProxy> > ConnectAsync(
            string server,
            int port,
            CreateProxyCallback createProxyCallback)
        {
            Contract.Requires(server != null);
            Contract.Requires(server.Length > 0);
            Contract.Requires(port > 0);
            Contract.Requires(createProxyCallback != null);

            m_logger.Debug(
                "Connecting to {0} with timeout {1} ms",
                GetServerDescription(server, port),
                m_options.TimeoutInMs);

            NetlibConnectionConfig clientConfig = NetlibConnectionConfig.Default;

            clientConfig.Timeout = m_options.TimeoutInMs == 0 ? SocketConfiguration.InfiniteTimeout : TimeSpan.FromMilliseconds(m_options.TimeoutInMs);

            var connection = new NetlibConnection(clientConfig)
            {
                AlwaysReconnect = m_options.ReconnectAutomatically,
            };

            try
            {
                var completionSource = TaskSourceSlim.Create <SocketError>();
                connection.ConnectComplete += (sender, status) => completionSource.TrySetResult(status);
                connection.Disconnected    += (sender, status) =>
                                              m_logger.Debug("Disconnected from {0} ({1})", GetServerDescription(server, port), status);

                // NetlibConnection uses Dns.GetDnsEntry to resolve even if the server string contains an IP address.
                // CB uses IPs in the production environment and reverse lookup is not available there.
                // IP address can also belong to a machine behind a VIP where reverse lookup doesn't make sense.
                IPAddress ip;
                if (IPAddress.TryParse(server, out ip))
                {
                    connection.ConnectAsync(new IPEndPoint(ip, port));
                }
                else
                {
                    connection.ConnectAsync(server, port);
                }

                var result = await completionSource.Task;

                return(OnConnectComplete(server, port, createProxyCallback, connection, result));
            }
            catch (Exception)
            {
                connection.Dispose();
                throw;
            }
        }
Пример #27
0
        /// <summary>
        /// Constructor
        /// </summary>
        protected Worker(uint workerId, string name)
        {
            WorkerId                = workerId;
            Name                    = name;
            m_workerSemaphores      = new SemaphoreSet <StringId>();
            m_workerPipStateManager = new WorkerPipStateManager();
            PipStateSnapshot        = m_workerPipStateManager.GetSnapshot();

            m_workerOperationKind = OperationKind.Create("Worker " + Name);
            DrainCompletion       = TaskSourceSlim.Create <bool>();
        }
Пример #28
0
        public Task TestHasherNotCorruptedByDelayedWrite()
        {
            return(TestHasherAsync(
                       async hasher =>
            {
                var content = ThreadSafeRandom.GetBytes(1000);

                HashAlgorithm algorithm;
                using (var token = hasher.CreateToken())
                {
                    // Capture hash algorithm from pool

                    // WHAT???????
                    algorithm = token.Hasher;
                }

                if (algorithm is IHashAlgorithmInputLength setInputLength)
                {
                    setInputLength.SetInputLength(content.Length);
                }

                var startTaskSource = TaskSourceSlim.Create <bool>();
                var completeTaskSource = TaskSourceSlim.Create <bool>();

                Task writeTask = null;

                using (var destinationStream = new PausedMemoryStream(startTaskSource, completeTaskSource))
                    using (var hashingDestinationStream = hasher.CreateWriteHashingStream(content.Length, destinationStream))
                    {
                        writeTask = hashingDestinationStream.WriteAsync(content, 0, content.Length);

                        // Wait for write operation to reach inner paused stream
                        await startTaskSource.Task;
                    }

                // Stream is now disposed (meaning hasher is returned to pool)
                // Allow write operation to complete which could attempt to write to the underlying hash algorithm
                // if the operation is not properly guarded
                completeTaskSource.SetResult(true);

                // Wait for write task to complete
                await writeTask;

                // This should be the same HashAlgorithm which was used by the hashing stream
                // in the pool. We detect if the HashAlgorithm is corrupted by attempting to hash with
                // empty content which should give the empty hash.
                if (algorithm is IHashAlgorithmInputLength setInputLength2)
                {
                    setInputLength2.SetInputLength(0);
                }
                var hash = algorithm.ComputeHash(new byte[0], 0, 0);
                Assert.Equal(hasher.Info.EmptyHash, new ContentHash(hasher.Info.HashType, hash));
            }));
        }
Пример #29
0
        public async Task <bool> WaitAsync(TimeSpan timeout, CancellationToken token)
        {
            if (_order == SemaphoreOrder.NonDeterministic)
            {
                // Forcing the same exception to be propagated for non-deterministic case as well.
                // SemaphoreSlim.WaitAsync throws OperationCanceledException but this method
                // should throw TaskCanceledException instead.
                try
                {
                    return(await _semaphore.WaitAsync(timeout, token));
                }
                catch (OperationCanceledException) when(token.IsCancellationRequested)
                {
                    throw new TaskCanceledException();
                }
            }

            var item = TaskSourceSlim.Create <bool>();

            var added = _collection.TryAdd(item);

            Contract.Assert(added, "Since collection is unbounded, it should always be able to add more items.");

            // Increment collection count
            _collectionCount.Release();

            using var delayCancellation = CancellationTokenSource.CreateLinkedTokenSource(token);
            var delay = Task.Delay(timeout, delayCancellation.Token);
            var task  = item.Task;

            if (delay == await Task.WhenAny(delay, task))
            {
                if (token.IsCancellationRequested)
                {
                    // Was unable to complete because the timeout was actually cancelled via the token passed in to WaitAsync,
                    // not because we actually timed out.
                    item.TrySetCanceled();
                }
                else
                {
                    // Timed out.
                    item.TrySetResult(false);
                }
            }
            else
            {
                // Clean up the delay task.
                delayCancellation.Cancel();
            }

            return(await task);
        }
Пример #30
0
        internal static void FeedOutputBuilder(SandboxedProcessOutputBuilder output, TaskSourceSlim <Unit> signalCompletion, string line)
        {
            if (signalCompletion.Task.IsCompleted)
            {
                return;
            }

            output.AppendLine(line);
            if (line == null)
            {
                signalCompletion.TrySetResult(Unit.Void);
            }
        }