Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.Windows.cs')
-rw-r--r--src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.Windows.cs138
1 files changed, 119 insertions, 19 deletions
diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.Windows.cs b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.Windows.cs
index 6d0e937dc..e9fe5485b 100644
--- a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.Windows.cs
+++ b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeThread.Windows.cs
@@ -21,8 +21,13 @@ namespace Internal.Runtime.Augments
[ThreadStatic]
private static ApartmentType t_apartmentType;
+ [ThreadStatic]
+ private static bool t_comInitializedByUs;
+
private SafeWaitHandle _osHandle;
+ private ApartmentState _initialAppartmentState = ApartmentState.Unknown;
+
/// <summary>
/// Used by <see cref="WaitHandle"/>'s multi-wait functions
/// </summary>
@@ -99,7 +104,7 @@ namespace Internal.Runtime.Augments
// Throw an ApplicationException for compatibility with CoreCLR. First save the error code.
int errorCode = Marshal.GetLastWin32Error();
var ex = new ApplicationException();
- ex.SetErrorCode(errorCode);
+ ex.HResult = errorCode;
throw ex;
}
@@ -283,10 +288,103 @@ namespace Internal.Runtime.Augments
return 0;
}
- public ApartmentState GetApartmentState() { throw null; }
- public bool TrySetApartmentState(ApartmentState state) { throw null; }
- public void DisableComObjectEagerCleanup() { throw null; }
- public void Interrupt() { throw null; }
+ public ApartmentState GetApartmentState()
+ {
+ if (this != CurrentThread)
+ {
+ if (HasStarted())
+ throw new ThreadStateException();
+ return _initialAppartmentState;
+ }
+
+ switch (GetCurrentApartmentType())
+ {
+ case ApartmentType.STA:
+ return ApartmentState.STA;
+ case ApartmentType.MTA:
+ return ApartmentState.MTA;
+ default:
+ return ApartmentState.Unknown;
+ }
+ }
+
+ public bool TrySetApartmentState(ApartmentState state)
+ {
+ if (this != CurrentThread)
+ {
+ using (LockHolder.Hold(_lock))
+ {
+ if (HasStarted())
+ throw new ThreadStateException();
+ _initialAppartmentState = state;
+ return true;
+ }
+ }
+
+ if (state != ApartmentState.Unknown)
+ {
+ InitializeCom(state);
+ }
+ else
+ {
+ UninitializeCom();
+ }
+
+ // Clear the cache and check whether new state matches the desired state
+ t_apartmentType = ApartmentType.Unknown;
+ return state == GetApartmentState();
+ }
+
+ private void InitializeComOnNewThread()
+ {
+ InitializeCom(_initialAppartmentState);
+ }
+
+ internal static void InitializeCom(ApartmentState state = ApartmentState.MTA)
+ {
+ if (t_comInitializedByUs)
+ return;
+
+#if ENABLE_WINRT
+ int hr = Interop.WinRT.RoInitialize(
+ (state == ApartmentState.STA) ? Interop.WinRT.RO_INIT_SINGLETHREADED
+ : Interop.WinRT.RO_INIT_MULTITHREADED);
+#else
+ int hr = Interop.Ole32.CoInitializeEx(IntPtr.Zero,
+ (state == ApartmentState.STA) ? Interop.Ole32.COINIT_APARTMENTTHREADED
+ : Interop.Ole32.COINIT_MULTITHREADED);
+#endif
+ // RPC_E_CHANGED_MODE indicates this thread has been already initialized with a different
+ // concurrency model. We stay away and let whoever else initialized the COM to be in control.
+ if (hr == HResults.RPC_E_CHANGED_MODE)
+ return;
+ if (hr < 0)
+ throw new OutOfMemoryException();
+
+ t_comInitializedByUs = true;
+
+ // If the thread has already been CoInitialized to the proper mode, then
+ // we don't want to leave an outstanding CoInit so we CoUninit.
+ if (hr > 0)
+ UninitializeCom();
+ }
+
+ private static void UninitializeCom()
+ {
+ if (!t_comInitializedByUs)
+ return;
+
+#if ENABLE_WINRT
+ Interop.WinRT.RoUninitialize();
+#else
+ Interop.Ole32.CoUninitialize();
+#endif
+ t_comInitializedByUs = false;
+ }
+
+ // TODO: https://github.com/dotnet/corefx/issues/20766
+ public void DisableComObjectEagerCleanup() { }
+ public void Interrupt() { throw new PlatformNotSupportedException(); }
internal static void UninterruptibleSleep0()
{
@@ -324,40 +422,40 @@ namespace Internal.Runtime.Augments
if (currentThreadType != ApartmentType.Unknown)
return currentThreadType;
- Interop._APTTYPE aptType;
- Interop._APTTYPEQUALIFIER aptTypeQualifier;
- int result = Interop.mincore.CoGetApartmentType(out aptType, out aptTypeQualifier);
+ Interop.APTTYPE aptType;
+ Interop.APTTYPEQUALIFIER aptTypeQualifier;
+ int result = Interop.Ole32.CoGetApartmentType(out aptType, out aptTypeQualifier);
ApartmentType type = ApartmentType.Unknown;
- switch ((Interop.Constants)result)
+ switch (result)
{
- case Interop.Constants.CoENotInitialized:
+ case HResults.CO_E_NOTINITIALIZED:
type = ApartmentType.None;
break;
- case Interop.Constants.SOk:
+ case HResults.S_OK:
switch (aptType)
{
- case Interop._APTTYPE.APTTYPE_STA:
- case Interop._APTTYPE.APTTYPE_MAINSTA:
+ case Interop.APTTYPE.APTTYPE_STA:
+ case Interop.APTTYPE.APTTYPE_MAINSTA:
type = ApartmentType.STA;
break;
- case Interop._APTTYPE.APTTYPE_MTA:
+ case Interop.APTTYPE.APTTYPE_MTA:
type = ApartmentType.MTA;
break;
- case Interop._APTTYPE.APTTYPE_NA:
+ case Interop.APTTYPE.APTTYPE_NA:
switch (aptTypeQualifier)
{
- case Interop._APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_MTA:
- case Interop._APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_IMPLICIT_MTA:
+ case Interop.APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_MTA:
+ case Interop.APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_IMPLICIT_MTA:
type = ApartmentType.MTA;
break;
- case Interop._APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_STA:
- case Interop._APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_MAINSTA:
+ case Interop.APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_STA:
+ case Interop.APTTYPEQUALIFIER.APTTYPEQUALIFIER_NA_ON_MAINSTA:
type = ApartmentType.STA;
break;
@@ -386,5 +484,7 @@ namespace Internal.Runtime.Augments
STA,
MTA
}
+
+ private static int ComputeCurrentProcessorId() => (int)Interop.mincore.GetCurrentProcessorNumber();
}
}