xamarin-macios/tests/xharness/TestTasks/Resource.cs

94 строки
2.7 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
namespace Xharness.TestTasks
{
// This is a very simple class to manage the general concept of 'resource'.
// Performance isn't important, so this is very simple.
// Currently it's only used to make sure everything that happens on the desktop
// is serialized (Jenkins.DesktopResource), but in the future the idea is to
// make each connected device a separate resource, which will make it possible
// to run tests in parallel across devices (and at the same time use the desktop
// to build the next test project).
public class Resource
{
public string Name;
public string Description;
ConcurrentQueue<TaskCompletionSource<IAcquiredResource>> queue = new ConcurrentQueue<TaskCompletionSource<IAcquiredResource>> ();
ConcurrentQueue<TaskCompletionSource<IAcquiredResource>> exclusive_queue = new ConcurrentQueue<TaskCompletionSource<IAcquiredResource>> ();
bool exclusive;
public int Users { get; private set; }
public int QueuedUsers => queue.Count + exclusive_queue.Count;
public int MaxConcurrentUsers { get; set; } = 1;
public Resource (string name, int max_concurrent_users = 1, string description = null)
{
this.Name = name;
this.MaxConcurrentUsers = max_concurrent_users;
this.Description = description ?? name;
}
public Task<IAcquiredResource> AcquireConcurrentAsync ()
{
lock (queue) {
if (!exclusive && Users < MaxConcurrentUsers) {
Users++;
return Task.FromResult<IAcquiredResource> (new AcquiredResource (this));
} else {
var tcs = new TaskCompletionSource<IAcquiredResource> (new AcquiredResource (this));
queue.Enqueue (tcs);
return tcs.Task;
}
}
}
public Task<IAcquiredResource> AcquireExclusiveAsync ()
{
lock (queue) {
if (Users == 0) {
Users++;
exclusive = true;
return Task.FromResult<IAcquiredResource> (new AcquiredResource (this));
} else {
var tcs = new TaskCompletionSource<IAcquiredResource> (new AcquiredResource (this));
exclusive_queue.Enqueue (tcs);
return tcs.Task;
}
}
}
void Release ()
{
lock (queue) {
Users--;
exclusive = false;
if (queue.TryDequeue (out TaskCompletionSource<IAcquiredResource> tcs)) {
Users++;
tcs.SetResult ((IAcquiredResource) tcs.Task.AsyncState);
} else if (Users == 0 && exclusive_queue.TryDequeue (out tcs)) {
Users++;
exclusive = true;
tcs.SetResult ((IAcquiredResource) tcs.Task.AsyncState);
}
}
}
class AcquiredResource : IAcquiredResource
{
public AcquiredResource (Resource resource)
{
this.Resource = resource;
}
void IDisposable.Dispose ()
{
Resource.Release ();
}
public Resource Resource { get; }
}
}
}