Xamarin Public Jenkins (auto-signing) e46a49ecf1 Imported Upstream version 5.10.0.47
Former-commit-id: d0813289fa2d35e1f8ed77530acb4fb1df441bc0
2018-01-24 17:04:36 +00:00

723 lines
22 KiB
C#

//
// System.Threading.Thread.cs
//
// Author:
// Dick Porter (dick@ximian.com)
//
// (C) Ximian, Inc. http://www.ximian.com
// Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.Runtime.Remoting.Contexts;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Permissions;
using System.Security.Principal;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.IO;
using System.Collections.Generic;
using System.Reflection;
using System.Security;
using System.Diagnostics;
using System.Runtime.ConstrainedExecution;
namespace System.Threading {
[StructLayout (LayoutKind.Sequential)]
sealed class InternalThread : CriticalFinalizerObject {
#pragma warning disable 169, 414, 649
#region Sync with metadata/object-internals.h
int lock_thread_id;
// stores a thread handle
IntPtr handle;
IntPtr native_handle; // used only on Win32
IntPtr unused3;
/* accessed only from unmanaged code */
private IntPtr name;
private int name_len;
private ThreadState state;
private object abort_exc;
private int abort_state_handle;
/* thread_id is only accessed from unmanaged code */
internal Int64 thread_id;
private IntPtr debugger_thread; // FIXME switch to bool as soon as CI testing with corlib version bump works
private UIntPtr static_data; /* GC-tracked */
private IntPtr runtime_thread_info;
/* current System.Runtime.Remoting.Contexts.Context instance
keep as an object to avoid triggering its class constructor when not needed */
private object current_appcontext;
private object root_domain_thread;
internal byte[] _serialized_principal;
internal int _serialized_principal_version;
private IntPtr appdomain_refs;
private int interruption_requested;
private IntPtr synch_cs;
internal bool threadpool_thread;
private bool thread_interrupt_requested;
/* These are used from managed code */
internal int stack_size;
internal byte apartment_state;
internal volatile int critical_region_level;
internal int managed_id;
private int small_id;
private IntPtr manage_callback;
private IntPtr unused4;
private IntPtr flags;
private IntPtr thread_pinning_ref;
private IntPtr abort_protected_block_count;
private int priority = (int) ThreadPriority.Normal;
private IntPtr owned_mutex;
private IntPtr suspended_event;
private int self_suspended;
/*
* These fields are used to avoid having to increment corlib versions
* when a new field is added to the unmanaged MonoThread structure.
*/
private IntPtr unused1;
private IntPtr unused2;
/* This is used only to check that we are in sync between the representation
* of MonoInternalThread in native and InternalThread in managed
*
* DO NOT RENAME! DO NOT ADD FIELDS AFTER! */
private IntPtr last;
#endregion
#pragma warning restore 169, 414, 649
// Closes the system thread handle
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void Thread_free_internal();
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
~InternalThread() {
Thread_free_internal();
}
}
[StructLayout (LayoutKind.Sequential)]
public sealed partial class Thread {
#pragma warning disable 414
#region Sync with metadata/object-internals.h
private InternalThread internal_thread;
object m_ThreadStartArg;
object pending_exception;
#endregion
#pragma warning restore 414
IPrincipal principal;
int principal_version;
// the name of current_thread is
// important because they are used by the runtime.
[ThreadStatic]
static Thread current_thread;
// can be both a ThreadStart and a ParameterizedThreadStart
private MulticastDelegate m_Delegate;
private ExecutionContext m_ExecutionContext; // this call context follows the logical thread
private bool m_ExecutionContextBelongsToOuterScope;
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void ConstructInternalThread ();
private InternalThread Internal {
get {
if (internal_thread == null)
ConstructInternalThread ();
return internal_thread;
}
}
public static Context CurrentContext {
[SecurityPermission (SecurityAction.LinkDemand, Infrastructure=true)]
get {
return(AppDomain.InternalGetContext ());
}
}
/*
* These two methods return an array in the target
* domain with the same content as the argument. If
* the argument is already in the target domain, then
* the argument is returned, otherwise a copy.
*/
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static byte[] ByteArrayToRootDomain (byte[] arr);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static byte[] ByteArrayToCurrentDomain (byte[] arr);
static void DeserializePrincipal (Thread th)
{
MemoryStream ms = new MemoryStream (ByteArrayToCurrentDomain (th.Internal._serialized_principal));
int type = ms.ReadByte ();
if (type == 0) {
BinaryFormatter bf = new BinaryFormatter ();
th.principal = (IPrincipal) bf.Deserialize (ms);
th.principal_version = th.Internal._serialized_principal_version;
} else if (type == 1) {
BinaryReader reader = new BinaryReader (ms);
string name = reader.ReadString ();
string auth_type = reader.ReadString ();
int n_roles = reader.ReadInt32 ();
string [] roles = null;
if (n_roles >= 0) {
roles = new string [n_roles];
for (int i = 0; i < n_roles; i++)
roles [i] = reader.ReadString ();
}
th.principal = new GenericPrincipal (new GenericIdentity (name, auth_type), roles);
} else if (type == 2 || type == 3) {
string [] roles = type == 2 ? null : new string [0];
th.principal = new GenericPrincipal (new GenericIdentity ("", ""), roles);
}
}
static void SerializePrincipal (Thread th, IPrincipal value)
{
MemoryStream ms = new MemoryStream ();
bool done = false;
if (value.GetType () == typeof (GenericPrincipal)) {
GenericPrincipal gp = (GenericPrincipal) value;
if (gp.Identity != null && gp.Identity.GetType () == typeof (GenericIdentity)) {
GenericIdentity id = (GenericIdentity) gp.Identity;
if (id.Name == "" && id.AuthenticationType == "") {
if (gp.Roles == null) {
ms.WriteByte (2);
done = true;
} else if (gp.Roles.Length == 0) {
ms.WriteByte (3);
done = true;
}
} else {
ms.WriteByte (1);
BinaryWriter br = new BinaryWriter (ms);
br.Write (gp.Identity.Name);
br.Write (gp.Identity.AuthenticationType);
string [] roles = gp.Roles;
if (roles == null) {
br.Write ((int) (-1));
} else {
br.Write (roles.Length);
foreach (string s in roles) {
br.Write (s);
}
}
br.Flush ();
done = true;
}
}
}
if (!done) {
ms.WriteByte (0);
BinaryFormatter bf = new BinaryFormatter ();
try {
bf.Serialize (ms, value);
} catch {}
}
th.Internal._serialized_principal = ByteArrayToRootDomain (ms.ToArray ());
}
public static IPrincipal CurrentPrincipal {
get {
Thread th = CurrentThread;
if (th.principal_version != th.Internal._serialized_principal_version)
th.principal = null;
if (th.principal != null)
return th.principal;
if (th.Internal._serialized_principal != null) {
try {
DeserializePrincipal (th);
return th.principal;
} catch {}
}
th.principal = GetDomain ().DefaultPrincipal;
th.principal_version = th.Internal._serialized_principal_version;
return th.principal;
}
[SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
set {
Thread th = CurrentThread;
if (value != GetDomain ().DefaultPrincipal) {
++th.Internal._serialized_principal_version;
try {
SerializePrincipal (th, value);
} catch (Exception) {
th.Internal._serialized_principal = null;
}
th.principal_version = th.Internal._serialized_principal_version;
} else {
th.Internal._serialized_principal = null;
}
th.principal = value;
}
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static Thread GetCurrentThread ();
public static Thread CurrentThread {
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
get {
Thread current = current_thread;
if (current != null)
return current;
// This will set the current_thread tls variable
return GetCurrentThread ();
}
}
internal static int CurrentThreadId {
get {
return (int)(CurrentThread.internal_thread.thread_id);
}
}
public static AppDomain GetDomain() {
return AppDomain.CurrentDomain;
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern static int GetDomainID();
// Returns the system thread handle
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern IntPtr Thread_internal (MulticastDelegate start);
private Thread (InternalThread it) {
internal_thread = it;
}
// part of ".NETPortable,Version=v4.0,Profile=Profile3" i.e. FX4 and SL4
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
~Thread ()
{
}
[Obsolete ("Deprecated in favor of GetApartmentState, SetApartmentState and TrySetApartmentState.")]
public ApartmentState ApartmentState {
get {
ValidateThreadState ();
return (ApartmentState)Internal.apartment_state;
}
set {
ValidateThreadState ();
TrySetApartmentState (value);
}
}
public bool IsThreadPoolThread {
get {
return IsThreadPoolThreadInternal;
}
}
internal bool IsThreadPoolThreadInternal {
get {
return Internal.threadpool_thread;
}
set {
Internal.threadpool_thread = value;
}
}
public bool IsAlive {
get {
ThreadState curstate = GetState (Internal);
if((curstate & ThreadState.Aborted) != 0 ||
(curstate & ThreadState.Stopped) != 0 ||
(curstate & ThreadState.Unstarted) != 0) {
return(false);
} else {
return(true);
}
}
}
public bool IsBackground {
get {
var state = ValidateThreadState ();
return (state & ThreadState.Background) != 0;
}
set {
ValidateThreadState ();
if (value) {
SetState (Internal, ThreadState.Background);
} else {
ClrState (Internal, ThreadState.Background);
}
}
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static string GetName_internal (InternalThread thread);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static void SetName_internal (InternalThread thread, String name);
/*
* The thread name must be shared by appdomains, so it is stored in
* unmanaged code.
*/
public string Name {
get {
return GetName_internal (Internal);
}
set {
SetName_internal (Internal, value);
}
}
public ThreadState ThreadState {
get {
return GetState (Internal);
}
}
#if MONO_FEATURE_THREAD_ABORT
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static void Abort_internal (InternalThread thread, object stateInfo);
[SecurityPermission (SecurityAction.Demand, ControlThread=true)]
public void Abort ()
{
Abort_internal (Internal, null);
}
[SecurityPermission (SecurityAction.Demand, ControlThread=true)]
public void Abort (object stateInfo)
{
Abort_internal (Internal, stateInfo);
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
extern object GetAbortExceptionState ();
internal object AbortReason {
get {
return GetAbortExceptionState ();
}
}
void ClearAbortReason ()
{
}
#else
[Obsolete ("Thread.Abort is not supported on the current platform.", true)]
public void Abort ()
{
throw new PlatformNotSupportedException ("Thread.Abort is not supported on the current platform.");
}
[Obsolete ("Thread.Abort is not supported on the current platform.", true)]
public void Abort (object stateInfo)
{
throw new PlatformNotSupportedException ("Thread.Abort is not supported on the current platform.");
}
[Obsolete ("Thread.ResetAbort is not supported on the current platform.", true)]
public static void ResetAbort ()
{
throw new PlatformNotSupportedException ("Thread.ResetAbort is not supported on the current platform.");
}
internal object AbortReason {
get {
throw new PlatformNotSupportedException ("Thread.ResetAbort is not supported on the current platform.");
}
}
#endif // MONO_FEATURE_THREAD_ABORT
[MethodImplAttribute (MethodImplOptions.InternalCall)]
private extern static void SpinWait_nop ();
[ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
public static void SpinWait (int iterations)
{
if (iterations < 0)
return;
while (iterations-- > 0)
{
SpinWait_nop ();
}
}
void StartInternal (IPrincipal principal, ref StackCrawlMark stackMark)
{
#if FEATURE_ROLE_BASED_SECURITY
Internal._serialized_principal = CurrentThread.Internal._serialized_principal;
#endif
// Thread_internal creates and starts the new thread,
if (Thread_internal(m_Delegate) == IntPtr.Zero)
throw new SystemException ("Thread creation failed.");
m_ThreadStartArg = null;
}
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern private static void SetState (InternalThread thread, ThreadState set);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern private static void ClrState (InternalThread thread, ThreadState clr);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern private static ThreadState GetState (InternalThread thread);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static byte VolatileRead (ref byte address);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static double VolatileRead (ref double address);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static short VolatileRead (ref short address);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static int VolatileRead (ref int address);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static long VolatileRead (ref long address);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static IntPtr VolatileRead (ref IntPtr address);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static object VolatileRead (ref object address);
[CLSCompliant(false)]
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static sbyte VolatileRead (ref sbyte address);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static float VolatileRead (ref float address);
[CLSCompliant (false)]
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static ushort VolatileRead (ref ushort address);
[CLSCompliant (false)]
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static uint VolatileRead (ref uint address);
[CLSCompliant (false)]
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static ulong VolatileRead (ref ulong address);
[CLSCompliant (false)]
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static UIntPtr VolatileRead (ref UIntPtr address);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref byte address, byte value);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref double address, double value);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref short address, short value);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref int address, int value);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref long address, long value);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref IntPtr address, IntPtr value);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref object address, object value);
[CLSCompliant(false)]
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref sbyte address, sbyte value);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref float address, float value);
[CLSCompliant (false)]
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref ushort address, ushort value);
[CLSCompliant (false)]
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref uint address, uint value);
[CLSCompliant (false)]
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref ulong address, ulong value);
[CLSCompliant (false)]
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern public static void VolatileWrite (ref UIntPtr address, UIntPtr value);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
extern static int SystemMaxStackStize ();
static int GetProcessDefaultStackSize (int maxStackSize)
{
if (maxStackSize == 0)
return 0;
if (maxStackSize < 131072) // make sure stack is at least 128k big
return 131072;
int page_size = Environment.GetPageSize ();
if ((maxStackSize % page_size) != 0) // round up to a divisible of page size
maxStackSize = (maxStackSize / (page_size - 1)) * page_size;
/* Respect the max stack size imposed by the system*/
return Math.Min (maxStackSize, SystemMaxStackStize ());
}
void SetStart (MulticastDelegate start, int maxStackSize)
{
m_Delegate = start;
Internal.stack_size = maxStackSize;
}
public int ManagedThreadId {
[ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
get {
return Internal.managed_id;
}
}
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
public static void BeginCriticalRegion ()
{
CurrentThread.Internal.critical_region_level++;
}
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
public static void EndCriticalRegion ()
{
CurrentThread.Internal.critical_region_level--;
}
[ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
public static void BeginThreadAffinity ()
{
// Managed and native threads are currently bound together.
}
[ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
public static void EndThreadAffinity ()
{
// Managed and native threads are currently bound together.
}
public ApartmentState GetApartmentState ()
{
ValidateThreadState ();
return (ApartmentState)Internal.apartment_state;
}
public void SetApartmentState (ApartmentState state)
{
if (!TrySetApartmentState (state))
throw new InvalidOperationException ("Failed to set the specified COM apartment state.");
}
public bool TrySetApartmentState (ApartmentState state)
{
if ((ThreadState & ThreadState.Unstarted) == 0)
throw new ThreadStateException ("Thread was in an invalid state for the operation being executed.");
if ((ApartmentState)Internal.apartment_state != ApartmentState.Unknown &&
(ApartmentState)Internal.apartment_state != state)
return false;
Internal.apartment_state = (byte)state;
return true;
}
[ComVisible (false)]
public override int GetHashCode ()
{
return ManagedThreadId;
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern void GetStackTraces (out Thread[] threads, out object[] stack_frames);
// This is a mono extension to gather the stack traces for all running threads
internal static Dictionary<Thread, StackTrace> Mono_GetStackTraces () {
Thread[] threads;
object[] stack_frames;
GetStackTraces (out threads, out stack_frames);
var res = new Dictionary<Thread, StackTrace> ();
for (int i = 0; i < threads.Length; ++i)
res [threads [i]] = new StackTrace ((StackFrame[])stack_frames [i]);
return res;
}
#if !MONO_FEATURE_THREAD_SUSPEND_RESUME
[Obsolete ("Thread.Suspend is not supported on the current platform.", true)]
public void Suspend ()
{
throw new PlatformNotSupportedException ("Thread.Suspend is not supported on the current platform.");
}
[Obsolete ("Thread.Resume is not supported on the current platform.", true)]
public void Resume ()
{
throw new PlatformNotSupportedException ("Thread.Resume is not supported on the current platform.");
}
#endif
public void DisableComObjectEagerCleanup ()
{
throw new PlatformNotSupportedException ();
}
ThreadState ValidateThreadState ()
{
var state = GetState (Internal);
if ((state & ThreadState.Stopped) != 0)
throw new ThreadStateException ("Thread is dead; state can not be accessed.");
return state;
}
}
}