forked from microsoft/CsWinRT
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMonoSupport.cs
More file actions
122 lines (102 loc) · 4.04 KB
/
MonoSupport.cs
File metadata and controls
122 lines (102 loc) · 4.04 KB
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
110
111
112
113
114
115
116
117
118
119
120
121
122
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
#pragma warning disable 0169 // The field 'xxx' is never used
#pragma warning disable 0649 // Field 'xxx' is never assigned to, and will always have its default value
namespace WinRT
{
internal static class Mono
{
static Lazy<bool> _usingMono = new Lazy<bool>(() =>
{
var modulePtr = Platform.LoadLibraryExW("mono-2.0-bdwgc.dll", IntPtr.Zero, 0);
if (modulePtr == IntPtr.Zero) return false;
if (!Platform.FreeLibrary(modulePtr))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
return true;
});
[DllImport("mono-2.0-bdwgc.dll")]
static extern IntPtr mono_thread_current();
[DllImport("mono-2.0-bdwgc.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool mono_thread_is_foreign(IntPtr threadPtr);
[DllImport("mono-2.0-bdwgc.dll")]
static extern void mono_unity_thread_fast_attach(IntPtr domainPtr);
[DllImport("mono-2.0-bdwgc.dll")]
static extern void mono_unity_thread_fast_detach();
[DllImport("mono-2.0-bdwgc.dll")]
static extern void mono_thread_pop_appdomain_ref();
[DllImport("mono-2.0-bdwgc.dll")]
static extern IntPtr mono_domain_get();
struct MonoObject
{
IntPtr vtable;
IntPtr synchronisation; // sic
}
unsafe struct MonoThread
{
MonoObject obj;
public MonoInternalThread_x64* internal_thread;
IntPtr start_obj;
IntPtr pending_exception;
}
[Flags]
enum MonoThreadFlag : int
{
MONO_THREAD_FLAG_DONT_MANAGE = 1,
MONO_THREAD_FLAG_NAME_SET = 2,
MONO_THREAD_FLAG_APPDOMAIN_ABORT = 4,
}
[StructLayout(LayoutKind.Explicit)]
struct MonoInternalThread_x64
{
[FieldOffset(0xd0)]
public MonoThreadFlag flags;
}
public sealed class ThreadContext : IDisposable
{
static Lazy<HashSet<IntPtr>> _foreignThreads = new Lazy<HashSet<IntPtr>>();
readonly IntPtr _threadPtr = IntPtr.Zero;
public ThreadContext()
{
if (_usingMono.Value)
{
// nothing to do for Mono-native threads
var threadPtr = mono_thread_current();
if (mono_thread_is_foreign(threadPtr))
{
// initialize this thread the first time it runs managed code, and remember it for future reference
if (_foreignThreads.Value.Add(threadPtr))
{
// clear initial appdomain ref for new foreign threads to avoid deadlock on domain unload
mono_thread_pop_appdomain_ref();
unsafe
{
// tell Mono to ignore the thread on process shutdown since there's nothing to synchronize with
((MonoThread*)threadPtr)->internal_thread->flags |= MonoThreadFlag.MONO_THREAD_FLAG_DONT_MANAGE;
}
}
unsafe
{
// attach as Unity does to set up the proper domain for the call
mono_unity_thread_fast_attach(mono_domain_get());
_threadPtr = threadPtr;
}
}
}
}
public void Dispose()
{
if (_threadPtr != IntPtr.Zero)
{
// detach as Unity does to properly reset the domain context
mono_unity_thread_fast_detach();
}
}
}
}
}