mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-15 09:35:37 -05:00
* Strings sweep for connection service * String sweep for credentials service * String sweep for hosting * String sweep for query execution service * String sweep for Workspace service * Renaming utility namespace to match standards Renaming Microsoft.SqlTools.EditorServices.Utility to Microsoft.SqlTools.ServiceLayer.Utility to match the naming changes done a while back. Also renaming them on the files that use them * Namespace change on reliable connection * Adding the new resx and designer files * Final bug fixes for srgen Fixing flakey moq package name * Removing todo as per @kevcunnane * Adding using statements as per @llali's comment * Fixing issues from broken unit tests Note: This feature contains changes that will break the contract for saving as CSV and JSON. On success, null is returned as a message instead of "Success". Changes will be made to the vscode component to handle this change.
104 lines
2.9 KiB
C#
104 lines
2.9 KiB
C#
//
|
|
// Copyright (c) Microsoft. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
//
|
|
|
|
using System;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Microsoft.SqlTools.ServiceLayer.Utility
|
|
{
|
|
/// <summary>
|
|
/// Provides a simple wrapper over a SemaphoreSlim to allow
|
|
/// synchronization locking inside of async calls. Cannot be
|
|
/// used recursively.
|
|
/// </summary>
|
|
public class AsyncLock
|
|
{
|
|
#region Fields
|
|
|
|
private Task<IDisposable> lockReleaseTask;
|
|
private SemaphoreSlim lockSemaphore = new SemaphoreSlim(1, 1);
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the AsyncLock class.
|
|
/// </summary>
|
|
public AsyncLock()
|
|
{
|
|
this.lockReleaseTask =
|
|
Task.FromResult(
|
|
(IDisposable)new LockReleaser(this));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Locks
|
|
/// </summary>
|
|
/// <returns>A task which has an IDisposable</returns>
|
|
public Task<IDisposable> LockAsync()
|
|
{
|
|
return this.LockAsync(CancellationToken.None);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Obtains or waits for a lock which can be used to synchronize
|
|
/// access to a resource. The wait may be cancelled with the
|
|
/// given CancellationToken.
|
|
/// </summary>
|
|
/// <param name="cancellationToken">
|
|
/// A CancellationToken which can be used to cancel the lock.
|
|
/// </param>
|
|
/// <returns></returns>
|
|
public Task<IDisposable> LockAsync(CancellationToken cancellationToken)
|
|
{
|
|
Task waitTask = lockSemaphore.WaitAsync(cancellationToken);
|
|
|
|
return waitTask.IsCompleted ?
|
|
this.lockReleaseTask :
|
|
waitTask.ContinueWith(
|
|
(t, releaser) =>
|
|
{
|
|
return (IDisposable)releaser;
|
|
},
|
|
this.lockReleaseTask.Result,
|
|
cancellationToken,
|
|
TaskContinuationOptions.ExecuteSynchronously,
|
|
TaskScheduler.Default);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private Classes
|
|
|
|
/// <summary>
|
|
/// Provides an IDisposable wrapper around an AsyncLock so
|
|
/// that it can easily be used inside of a 'using' block.
|
|
/// </summary>
|
|
private class LockReleaser : IDisposable
|
|
{
|
|
private AsyncLock lockToRelease;
|
|
|
|
internal LockReleaser(AsyncLock lockToRelease)
|
|
{
|
|
this.lockToRelease = lockToRelease;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
this.lockToRelease.lockSemaphore.Release();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|
|
|