tgstation-server 6.12.0
The /tg/station 13 server suite
Loading...
Searching...
No Matches
FifoSemaphore.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Threading;
4using System.Threading.Tasks;
5
7{
13 {
18 {
22 public bool Abandoned { get; set; }
23 }
24
28 readonly SemaphoreSlim semaphore;
29
33 readonly Queue<FifoSemaphoreTicket> ticketQueue;
34
39 {
40 ticketQueue = new Queue<FifoSemaphoreTicket>();
41 semaphore = new SemaphoreSlim(1);
42 }
43
45 public void Dispose() => semaphore.Dispose();
46
52 public async ValueTask<SemaphoreSlimContext> Lock(CancellationToken cancellationToken)
53 {
54 FifoSemaphoreTicket? ticket = null;
55 using (cancellationToken.Register(
56 () =>
57 {
58 if (ticket != null)
59 ticket.Abandoned = true;
60 }))
61 while (true)
62 {
63 var context = await SemaphoreSlimContext.Lock(semaphore, cancellationToken);
64 try
65 {
66 FifoSemaphoreTicket? peekedTicket = null;
67 while (ticketQueue.Count > 0)
68 {
69 peekedTicket = ticketQueue.Peek();
70 if (peekedTicket.Abandoned)
71 ticketQueue.Dequeue();
72 else
73 break;
74 }
75
76 cancellationToken.ThrowIfCancellationRequested();
77
78 bool goTime;
79 if (ticketQueue.Count == 0)
80 goTime = true;
81 else if (ticket == null)
82 {
83 ticket = new FifoSemaphoreTicket();
84 cancellationToken.ThrowIfCancellationRequested();
85 ticketQueue.Enqueue(ticket);
86 goTime = false;
87 }
88 else
89 {
90 goTime = peekedTicket == ticket;
91 if (goTime)
92 ticketQueue.Dequeue();
93 }
94
95 if (goTime)
96 {
97 var localContext = context;
98 context = null;
99 return localContext;
100 }
101 }
102 finally
103 {
104 context?.Dispose();
105 }
106
107 await Task.Yield();
108 }
109 }
110 }
111}
class to represent a ticket in the ticketQueue and whether or not it is Abandoned.
bool Abandoned
Set if the wait operation on a FifoSemaphore was cancelled to avoid clogging the queue.
A first-in first-out async semaphore.
async ValueTask< SemaphoreSlimContext > Lock(CancellationToken cancellationToken)
Locks the FifoSemaphore.
readonly Queue< FifoSemaphoreTicket > ticketQueue
The Queue<T> of ticket FifoSemaphoreTickets.
readonly SemaphoreSlim semaphore
The backing SemaphoreSlim.
FifoSemaphore()
Initializes a new instance of the FifoSemaphore class.
static async ValueTask< SemaphoreSlimContext > Lock(SemaphoreSlim semaphore, CancellationToken cancellationToken, ILogger? logger=null)
Asyncronously locks a semaphore .