Skip to content

Commit 3bb87cb

Browse files
committed
Basic implementation of AsyncManualResetEvent
1 parent 9f6dd2b commit 3bb87cb

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// This source code is dual-licensed under the Apache License, version
2+
// 2.0, and the Mozilla Public License, version 2.0.
3+
//
4+
// The APL v2.0:
5+
//
6+
//---------------------------------------------------------------------------
7+
// Copyright (c) 2007-2024 Broadcom. All Rights Reserved.
8+
//
9+
// Licensed under the Apache License, Version 2.0 (the "License");
10+
// you may not use this file except in compliance with the License.
11+
// You may obtain a copy of the License at
12+
//
13+
// https://www.apache.org/licenses/LICENSE-2.0
14+
//
15+
// Unless required by applicable law or agreed to in writing, software
16+
// distributed under the License is distributed on an "AS IS" BASIS,
17+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
// See the License for the specific language governing permissions and
19+
// limitations under the License.
20+
//---------------------------------------------------------------------------
21+
//
22+
// The MPL v2.0:
23+
//
24+
//---------------------------------------------------------------------------
25+
// This Source Code Form is subject to the terms of the Mozilla Public
26+
// License, v. 2.0. If a copy of the MPL was not distributed with this
27+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
28+
//
29+
// Copyright (c) 2007-2024 Broadcom. All Rights Reserved.
30+
//---------------------------------------------------------------------------
31+
32+
using System.Threading;
33+
using System.Threading.Tasks;
34+
35+
namespace RabbitMQ.Client.client.impl
36+
{
37+
/// <summary>
38+
/// Inspired by http://blogs.msdn.com/b/pfxteam/archive/2012/02/11/10266920.aspx
39+
/// </summary>
40+
sealed class AsyncManualResetEvent
41+
{
42+
public AsyncManualResetEvent(bool initialState)
43+
{
44+
if (initialState)
45+
{
46+
_taskCompletionSource.SetResult(true);
47+
}
48+
}
49+
50+
public bool IsSet => _taskCompletionSource.Task.IsCompleted;
51+
52+
public async Task WaitAsync(CancellationToken cancellationToken)
53+
{
54+
CancellationTokenRegistration tokenRegistration =
55+
#if NET6_0_OR_GREATER
56+
cancellationToken.UnsafeRegister(
57+
state => ((TaskCompletionSource<bool>)state!).TrySetCanceled(), _taskCompletionSource);
58+
#else
59+
cancellationToken.Register(
60+
state => ((TaskCompletionSource<bool>)state!).TrySetCanceled(),
61+
state: _taskCompletionSource, useSynchronizationContext: false);
62+
#endif
63+
try
64+
{
65+
await _taskCompletionSource.Task.ConfigureAwait(false);
66+
}
67+
finally
68+
{
69+
#if NET6_0_OR_GREATER
70+
await tokenRegistration.DisposeAsync()
71+
.ConfigureAwait(false);
72+
#else
73+
tokenRegistration.Dispose();
74+
#endif
75+
}
76+
}
77+
78+
public void Set()
79+
{
80+
_taskCompletionSource.TrySetResult(true);
81+
}
82+
83+
public void Reset()
84+
{
85+
var sw = new SpinWait();
86+
87+
do
88+
{
89+
var currentTaskCompletionSource = _taskCompletionSource;
90+
if (!currentTaskCompletionSource.Task.IsCompleted)
91+
{
92+
return;
93+
}
94+
95+
var nextTaskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
96+
if (Interlocked.CompareExchange(ref _taskCompletionSource, nextTaskCompletionSource, currentTaskCompletionSource) == currentTaskCompletionSource)
97+
{
98+
return;
99+
}
100+
101+
sw.SpinOnce();
102+
}
103+
while (true);
104+
}
105+
106+
volatile TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
107+
}
108+
}

0 commit comments

Comments
 (0)