/
ThreadPoolBoundHandle.Portable.cs
109 lines (88 loc) · 4.57 KB
/
ThreadPoolBoundHandle.Portable.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace System.Threading
{
//
// Implementation of ThreadPoolBoundHandle that sits on top of the CLR's ThreadPool and Overlapped infrastructure
//
/// <summary>
/// Represents an I/O handle that is bound to the system thread pool and enables low-level
/// components to receive notifications for asynchronous I/O operations.
/// </summary>
public sealed partial class ThreadPoolBoundHandle : IDisposable
{
private unsafe NativeOverlapped* AllocateNativeOverlappedPortableCore(IOCompletionCallback callback, object? state, object? pinData) =>
AllocateNativeOverlappedPortableCore(callback, state, pinData, flowExecutionContext: true);
private unsafe NativeOverlapped* UnsafeAllocateNativeOverlappedPortableCore(IOCompletionCallback callback, object? state, object? pinData) =>
AllocateNativeOverlappedPortableCore(callback, state, pinData, flowExecutionContext: false);
private unsafe NativeOverlapped* AllocateNativeOverlappedPortableCore(IOCompletionCallback callback, object? state, object? pinData, bool flowExecutionContext)
{
ArgumentNullException.ThrowIfNull(callback);
ObjectDisposedException.ThrowIf(_isDisposed, this);
ThreadPoolBoundHandleOverlapped overlapped = new ThreadPoolBoundHandleOverlapped(callback, state, pinData, preAllocated: null, flowExecutionContext);
overlapped._boundHandle = this;
return overlapped._nativeOverlapped;
}
private unsafe NativeOverlapped* AllocateNativeOverlappedPortableCore(PreAllocatedOverlapped preAllocated)
{
ArgumentNullException.ThrowIfNull(preAllocated);
ObjectDisposedException.ThrowIf(_isDisposed, this);
preAllocated.AddRef();
try
{
ThreadPoolBoundHandleOverlapped overlapped = preAllocated._overlappedPortableCore!;
if (overlapped._boundHandle != null)
throw new ArgumentException(SR.Argument_PreAllocatedAlreadyAllocated, nameof(preAllocated));
overlapped._boundHandle = this;
return overlapped._nativeOverlapped;
}
catch
{
preAllocated.Release();
throw;
}
}
private unsafe void FreeNativeOverlappedPortableCore(NativeOverlapped* overlapped)
{
ArgumentNullException.ThrowIfNull(overlapped);
// Note: we explicitly allow FreeNativeOverlapped calls after the ThreadPoolBoundHandle has been Disposed.
ThreadPoolBoundHandleOverlapped wrapper = GetOverlappedWrapper(overlapped);
if (wrapper._boundHandle != this)
throw new ArgumentException(SR.Argument_NativeOverlappedWrongBoundHandle, nameof(overlapped));
if (wrapper._preAllocated != null)
wrapper._preAllocated.Release();
else
Overlapped.Free(overlapped);
}
private static unsafe object? GetNativeOverlappedStatePortableCore(NativeOverlapped* overlapped)
{
ArgumentNullException.ThrowIfNull(overlapped);
ThreadPoolBoundHandleOverlapped wrapper = GetOverlappedWrapper(overlapped);
Debug.Assert(wrapper._boundHandle != null);
return wrapper._userState;
}
private static unsafe ThreadPoolBoundHandleOverlapped GetOverlappedWrapper(NativeOverlapped* overlapped)
{
ThreadPoolBoundHandleOverlapped wrapper;
try
{
wrapper = (ThreadPoolBoundHandleOverlapped)Overlapped.Unpack(overlapped);
}
catch (NullReferenceException ex)
{
throw new ArgumentException(SR.Argument_NativeOverlappedAlreadyFree, nameof(overlapped), ex);
}
return wrapper;
}
private void DisposePortableCore()
{
// .NET Native's version of ThreadPoolBoundHandle that wraps the Win32 ThreadPool holds onto
// native resources so it needs to be disposable. To match the contract, we are also disposable.
// We also implement a disposable state to mimic behavior between this implementation and
// .NET Native's version (code written against us, will also work against .NET Native's version).
_isDisposed = true;
}
}
}