private async Task AcceptNewClientAsync( TcpClient client, ConnectionSetting connectionSettings, CancellationToken cancellationToken) { ILifetimeScope newScope = _scope.BeginLifetimeScope( ConnectionScopeTag, builder => { builder.RegisterInstance( new ConnectionInformation( client.Client.LocalEndPoint.ToString(), client.Client.RemoteEndPoint.ToString())); builder.RegisterInstance(new SecurableConnection(client.GetStream(), _keyProvider.GetKey(connectionSettings.Certificate))) .As <SecurableConnection>() .As <IConnectionSecurity>() .As <IVariableStreamReader>(); builder.RegisterInstance(connectionSettings); builder.Register(c => c.ResolveKeyed <IAuthenticationTransport>(connectionSettings.Protocol)) .As <IAuthenticationTransport>(); } ); var newSession = newScope.ResolveKeyed <IProtocolSession>(connectionSettings.Protocol); using (await SemaphoreLock.GetLockAsync(_sessionSemaphore, cancellationToken)) { _sessions.Add(new SessionHolder(newSession, newSession.RunAsync(cancellationToken), newScope)); } }
public async Task <Solution> ProcessAsync( Document document, SyntaxNode syntaxRoot, CancellationToken cancellationToken) { if (m_unwrittenWritableFields == null) { using (await SemaphoreLock.GetAsync(m_processUsagesLock)) { // A global analysis must be run before we can do any actual processing, because a field might // be written in a different file than it is declared (even private ones may be split between // partial classes). // It's also quite expensive, which is why it's being done inside the lock, so // that the entire solution is not processed for each input file individually if (m_unwrittenWritableFields == null) { List <Document> allDocuments = document.Project.Solution.Projects.SelectMany(p => p.Documents).ToList(); HashSet <IFieldSymbol>[] fields = await Task.WhenAll( allDocuments .AsParallel() .Select( doc => WritableFieldScanner.Scan(doc, cancellationToken))); var writableFields = new ConcurrentDictionary <IFieldSymbol, bool>( fields.SelectMany(s => s).Select(f => new KeyValuePair <IFieldSymbol, bool>(f, true))); await Task.WhenAll( allDocuments.AsParallel() .Select( doc => WriteUsagesScanner.RemoveWrittenFields( doc, writableFields, cancellationToken))); m_unwrittenWritableFields = writableFields; } } } if (m_unwrittenWritableFields.Count == 0) { // If there are no unwritten writable fields, skip all the rewriting return(document.Project.Solution); } SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken); var application = new ReadonlyRewriter( m_unwrittenWritableFields, await document.GetSemanticModelAsync(cancellationToken)); return(document.Project.Solution.WithDocumentSyntaxRoot(document.Id, application.Visit(root))); }
public async Task RunAsync(CancellationToken cancellationToken) { _log.Information($"Opening ports: {string.Join(",", _settings.Connections.Select(p => p.Port.ToString()))}"); TcpListener[] listeners = _settings.Connections .Select(p => new TcpListener(IPAddress.Any, p.Port)) .ToArray(); foreach (TcpListener l in listeners) { l.Start(); } Task <TcpClient>[] listenerTasks = listeners .Select(tcp => tcp.AcceptTcpClientAsync()) .ToArray(); while (!cancellationToken.IsCancellationRequested) { var tasks = new Task[listenerTasks.Length + _sessions.Count]; Array.Copy(listenerTasks, 0, tasks, 0, listenerTasks.Length); _sessions.Select(s => s.Task).ToList().CopyTo(tasks, listenerTasks.Length); int completedIndex = Task.WaitAny(tasks); Task task = tasks[completedIndex]; if (task is Task <TcpClient> tcpTask) { // This is a new connection task TcpClient client = tcpTask.Result; ConnectionSetting connectionSettings = _settings.Connections[completedIndex]; await AcceptNewClientAsync(client, connectionSettings, cancellationToken); // Wait for another connection listenerTasks[completedIndex] = listeners[completedIndex].AcceptTcpClientAsync(); } else { // One of the existing connections is closing using (await SemaphoreLock.GetLockAsync(_sessionSemaphore, cancellationToken)) { int sessionIndex = completedIndex - listenerTasks.Length; SessionHolder closingSession = _sessions[sessionIndex]; _log.Information($"Closing session {closingSession.Session.Id}..."); _sessions.RemoveAt(sessionIndex); closingSession.Scope.Dispose(); } } } foreach (TcpListener l in listeners) { l.Stop(); } }
public async Task Close(CancellationToken cancellationToken) { using (await SemaphoreLock.GetLockAsync(_sessionSemaphore, cancellationToken)) { Task[] closing = _sessions.Select(session => session.CloseAsync(cancellationToken)).ToArray(); Task.WaitAll(closing, cancellationToken); Task.WaitAll(_sessionLifetimes.ToArray(), cancellationToken); _sessions = null; _sessionLifetimes = null; } }
/// <summary> /// EncodeLock is used to encode a SemaphoreLock into a KVPair that can be PUT /// </summary> /// <param name="l">The SemaphoreLock data</param> /// <param name="oldIndex">The index that the data was fetched from, for CAS</param> /// <returns>A K/V pair with the lock data encoded in the Value field</returns> private KVPair EncodeLock(SemaphoreLock l, ulong oldIndex) { var jsonValue = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(l)); return(new KVPair(string.Join("/", Opts.Prefix, DefaultSemaphoreKey)) { Value = jsonValue, Flags = SemaphoreFlagValue, ModifyIndex = oldIndex }); }
public void ShouldReleaseTheLockOnRelease() { using var semaphore = new SemaphoreSlim(0, 1); Assert.AreEqual(0, semaphore.CurrentCount); var target = new SemaphoreLock(semaphore); target.Release(); Assert.AreEqual(1, semaphore.CurrentCount); }
/// <summary> /// EncodeLock is used to encode a SemaphoreLock into a KVPair that can be PUT /// </summary> /// <param name="l">The SemaphoreLock data</param> /// <param name="oldIndex">The index that the data was fetched from, for CAS</param> /// <returns>A K/V pair with the lock data encoded in the Value field</returns> private KVPair EncodeLock(SemaphoreLock l, ulong oldIndex) { var jsonValue = JsonSerializer.SerializeToUtf8Bytes(l); return(new KVPair(string.Join("/", Opts.Prefix, DefaultSemaphoreKey)) { Value = jsonValue, Flags = SemaphoreFlagValue, ModifyIndex = oldIndex }); }
public async Task Close(CancellationToken cancellationToken) { using (await SemaphoreLock.GetLockAsync(_sessionSemaphore, cancellationToken)) { foreach (SessionHolder session in _sessions) { session.Scope.Dispose(); } await Task.WhenAll(_sessions.Select(s => s.Task)); _sessions = null; } }
public static async Task <IDisposable> LockAsync(this SemaphoreSlim semaphore, CancellationToken cancellationToken) { var res = new SemaphoreLock(semaphore); try { await semaphore.WaitAsync(cancellationToken); var res2 = res; res = null; return(res2); } finally { res?.Reset(); } }
public void LockAndSleep() { ThreadedRepeat(100, (index, threadAsserter) => { int id = Thread.CurrentThread.ManagedThreadId; using (SemaphoreLock.Lock(semaphore)) { Thread.Sleep(400); Console.Out.WriteLine("Thread " + id + " IN critical section. " + Interlocked.Increment(ref countIn) + " Threads in critical section."); } Console.Out.WriteLine("Thread " + id + " OUT critical section. " + Interlocked.Decrement(ref countIn) + " Threads in critical section."); threadAsserter.Assert(() => Assert.Less(countIn, 5)); }); }
public static IDisposable Lock(this SemaphoreSlim semaphore) { var res = new SemaphoreLock(semaphore); try { try { semaphore.Wait(); var res2 = res; res = null; return(res2); } finally { res?.Reset(); } } catch (ObjectDisposedException ex) { throw new OperationCanceledException("semaphore was disposed", ex); } }
public static async Task <IDisposable> LockAsync(this SemaphoreSlim semaphore, CancellationToken cancellationToken) { var res = new SemaphoreLock(semaphore); try { try { await semaphore.WaitAsync(cancellationToken); var res2 = res; res = null; return(res2); } finally { res?.Reset(); } } catch (ObjectDisposedException ex) { throw new OperationCanceledException("semaphore was disposed", ex); } }
public void BasicLockingLogic_SeemsToWork() { // Start one long-running operation and one short-running one. // Expected behavior is that short one will wait for long one to complete. using (var semaphore = new SemaphoreSlim(1)) { int?longCompletedAt = null; int?shortCompletedAt = null; var longTask = Task.Run(async() => { Debug.WriteLine("Long entered."); using (await SemaphoreLock.TakeAsync(semaphore)) { Debug.WriteLine("Long acquired lock."); await Task.Delay(5000); Debug.WriteLine("Long completed."); longCompletedAt = Environment.TickCount; } }); var shortTask = Task.Run(async() => { Debug.WriteLine("Short entered."); await Task.Delay(500); Debug.WriteLine("Short starting work."); using (await SemaphoreLock.TakeAsync(semaphore)) { Debug.WriteLine("Short acquired lock."); await Task.Delay(50); Debug.WriteLine("Short completed."); shortCompletedAt = Environment.TickCount; } }); Task.WaitAll(longTask, shortTask); Assert.IsTrue(shortCompletedAt.HasValue); Assert.IsTrue(longCompletedAt.HasValue); Assert.IsTrue(longCompletedAt.Value < shortCompletedAt.Value); } }
public void Exception_Unlocks() { using (var semaphore = new SemaphoreSlim(1)) { try { using (SemaphoreLock.Take(semaphore)) { throw new InvalidProgramException(); } } catch (InvalidProgramException) { } // If this is false, the lock is still being held. Assert.IsTrue(semaphore.Wait(0)); } }
public async Task Start(CancellationToken cancellationToken) { TcpListener[] listeners = _ports .Select(p => new TcpListener(IPAddress.Any, p)) .ToArray(); foreach (var l in listeners) { l.Start(); } Task <TcpClient>[] tasks = listeners.Select(tcp => tcp.AcceptTcpClientAsync()) .ToArray(); while (!cancellationToken.IsCancellationRequested) { int taskCompleted = Task.WaitAny(tasks); TcpClient client = tasks[taskCompleted].Result; using (await SemaphoreLock.GetLockAsync(_sessionSemaphore, cancellationToken)) { var securableConnection = new SecurableConnection(client.GetStream()); securableConnection.Certificate = ServerCertificate; var session = InitiateSession( securableConnection, client.Client.LocalEndPoint, client.Client.RemoteEndPoint); _sessions.Add(session); _sessionLifetimes.Add(session.Start(cancellationToken)); } // Wait for another connection tasks[taskCompleted] = listeners[taskCompleted].AcceptTcpClientAsync(); } foreach (var l in listeners) { l.Stop(); } }
public async Task Run() { var sem = new SemaphoreLock(); var mut = new MutexLock(); var tasks = new List <Task>(); Console.WriteLine("Running blocking lock function..."); for (var i = 0; i < 3; i++) { tasks.Add(Task.Run(() => RunLock(sem))); tasks.Add(Task.Run(() => RunLock(mut))); } await Task.WhenAll(tasks); tasks = new List <Task>(); Console.WriteLine("Running non-blocking lock function..."); for (var i = 0; i < 3; i++) { tasks.Add(RunLockAsync(sem)); tasks.Add(RunLockAsync(mut)); } await Task.WhenAll(tasks); }
public async Task SendMessageAsync(ImapMessage message, Encoding encoding, CancellationToken cancellationToken) { using (await SemaphoreLock.GetLockAsync(_sendSemaphore, cancellationToken)) { var builder = new StringBuilder(); builder.Append(message.Tag); foreach (IMessageData data in message.Data) { if (data is LiteralMessageData literal) { builder.Append("}"); builder.Append(literal.Length); builder.AppendLine("}"); await _connection.WriteAsync(builder.ToString(), encoding, cancellationToken); builder.Clear(); } else { if (builder.Length > 0) { builder.Append(" "); } builder.Append(data.ToMessageString()); } } if (builder.Length > 0) { _logger.Verbose("IMAP -> " + builder); builder.AppendLine(); await _connection.WriteAsync(builder.ToString(), encoding, cancellationToken); } } }
/// <summary> /// PruneDeadHolders is used to remove all the dead lock holders /// </summary> /// <param name="l">The SemaphoreLock to prune</param> /// <param name="pairs">The list of K/V that currently hold locks</param> private static void PruneDeadHolders(SemaphoreLock l, IEnumerable <KVPair> pairs) { var alive = new HashSet <string>(); foreach (var pair in pairs) { if (!string.IsNullOrEmpty(pair.Session)) { alive.Add(pair.Session); } } var newHolders = new Dictionary <string, bool>(l.Holders); foreach (var holder in l.Holders) { if (!alive.Contains(holder.Key)) { newHolders.Remove(holder.Key); } } l.Holders = newHolders; }
/// <summary> /// EncodeLock is used to encode a SemaphoreLock into a KVPair that can be PUT /// </summary> /// <param name="l">The SemaphoreLock data</param> /// <param name="oldIndex">The index that the data was fetched from, for CAS</param> /// <returns>A K/V pair with the lock data encoded in the Value field</returns> private KVPair EncodeLock(SemaphoreLock l, ulong oldIndex) { var jsonValue = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(l)); return new KVPair(string.Join("/", Opts.Prefix, DefaultSemaphoreKey)) { Value = jsonValue, Flags = SemaphoreFlagValue, ModifyIndex = oldIndex }; }
/// <summary> /// PruneDeadHolders is used to remove all the dead lock holders /// </summary> /// <param name="l">The SemaphoreLock to prune</param> /// <param name="pairs">The list of K/V that currently hold locks</param> private static void PruneDeadHolders(SemaphoreLock l, IEnumerable<KVPair> pairs) { var alive = new HashSet<string>(); foreach (var pair in pairs) { if (!string.IsNullOrEmpty(pair.Session)) { alive.Add(pair.Session); } } var newHolders = new Dictionary<string, bool>(l.Holders); foreach (var holder in l.Holders) { if (!alive.Contains(holder.Key)) { newHolders.Remove(holder.Key); } } l.Holders = newHolders; }
/// <summary> /// Requests the tracker to update its data set. /// </summary> /// <remarks> /// May be called multiple times concurrently. /// /// The method returns to signal that the trackerss of all containers /// when the method was called have attempted an update to their data. /// It may be that some updates failed - all we can say is that we tried. /// /// Method does not throw exceptions on transient failures, merely logs and ignores them. /// </remarks> public async Task TryUpdateAsync() { using var cts = new CancellationTokenSource(Constants.MaxTotalUpdateDuration); // If we get this lock, we will actually perform the update. using var writeLock = await SemaphoreLock.TryTakeAsync(_updateLock, TimeSpan.Zero); if (writeLock == null) { // Otherwise, we just no-op once the earlier probe request has updated the data. await WaitForPredecessorUpdateAsync(cts.Token); return; } using var probeDurationTimer = DockerTrackerMetrics.ProbeDuration.NewTimer(); IList <ContainerListResponse> allContainers; try { using var listDurationTimer = DockerTrackerMetrics.ListContainersDuration.NewTimer(); allContainers = await _client.Containers.ListContainersAsync(new ContainersListParameters { All = true }, cts.Token); } catch (Exception ex) { DockerTrackerMetrics.ListContainersErrorCount.Inc(); _log.Error(Helpers.Debug.GetAllExceptionMessages(ex)); _log.Debug(ex.ToString()); // Only to verbose output. // Errors are ignored - if we fail to get data, we just skip an update and log the failure. // The next update will hopefully get past the error. // We will not remove the trackers yet but we will unpublish so we don't keep stale data published. foreach (var tracker in _containerTrackers.Values) { tracker.Unpublish(); } return; } DockerTrackerMetrics.ContainerCount.Set(allContainers.Count); SynchronizeTrackerSet(allContainers); // Update each tracker. We do them in parallel to minimize the total time span spent on probing. var updateTasks = new List <Task>(); foreach (var tracker in _containerTrackers.Values) { updateTasks.Add(tracker.TryUpdateAsync(_client, cts.Token)); } // Only exceptions from the update calls should be terminal exceptions, // so it is fine not to catch anything that may be thrown here. await Task.WhenAll(updateTasks); DockerTrackerMetrics.SuccessfulProbeTime.SetToCurrentTimeUtc(); }
private async Task WaitForPredecessorUpdateAsync(CancellationToken cancel) { _log.Debug("Will not trigger new probe as it overlaps with existing probe."); using var readLock = await SemaphoreLock.TakeAsync(_updateLock, cancel); }
public void LockingLogic_WithTimeout_SeemsToWork() { // Start one long-running operation and two short-running ones, where one of the shorts times out on the lock. using (var semaphore = new SemaphoreSlim(1)) { int?longCompletedAt = null; int?short1CompletedAt = null; int?short2CompletedAt = null; int?short1TimedOutAt = null; var longTask = Task.Run(async() => { Debug.WriteLine("Long entered."); using (await SemaphoreLock.TakeAsync(semaphore)) { Debug.WriteLine("Long acquired lock."); await Task.Delay(5000); Debug.WriteLine("Long completed."); longCompletedAt = Environment.TickCount; } }); var shortTask1 = Task.Run(async() => { Debug.WriteLine("Short1 entered."); await Task.Delay(500); Debug.WriteLine("Short1 starting work."); var lockInstance = await SemaphoreLock.TryTakeAsync(semaphore, TimeSpan.FromSeconds(1)); if (lockInstance == null) { Debug.WriteLine("Short1 timed out."); short1TimedOutAt = Environment.TickCount; } else { using (lockInstance) { Debug.WriteLine("Short1 acquired lock."); await Task.Delay(50); Debug.WriteLine("Short1 completed."); short1CompletedAt = Environment.TickCount; } } }); var shortTask2 = Task.Run(async() => { Debug.WriteLine("Short2 entered."); await Task.Delay(500); Debug.WriteLine("Short2 starting work."); using (await SemaphoreLock.TakeAsync(semaphore)) { Debug.WriteLine("Short2 acquired lock."); await Task.Delay(50); Debug.WriteLine("Short2 completed."); short2CompletedAt = Environment.TickCount; } }); Task.WaitAll(longTask, shortTask1, shortTask2); Assert.IsFalse(short1CompletedAt.HasValue); Assert.IsTrue(short1TimedOutAt.HasValue); Assert.IsTrue(short2CompletedAt.HasValue); Assert.IsTrue(longCompletedAt.HasValue); Assert.IsTrue(short1TimedOutAt.Value < longCompletedAt.Value); Assert.IsTrue(short1TimedOutAt.Value < short2CompletedAt.Value); Assert.IsTrue(longCompletedAt.Value < short2CompletedAt.Value); } }