context: // Threading-related stuff.
  //
  // Note: this was originally designed to support Compact Framework, but that has
  // since been dropped as a design goal.
  using System;
  using System.Collections.Generic;
  using System.Text;
  using System.Threading;
  using System.Diagnostics;
  #if !CompactFramework
  using System.Runtime.Serialization;
  #else
  namespace System.Threading
  {
  	public delegate void ParameterizedThreadStart(object obj);
  }
  #endif
  
  namespace Loyc.Threading
  {
  	/// <summary>Creates and controls a thread, and fills in a gap in the
  	/// .NET framework by propagating thread-local variables from parent
  	/// to child threads, and by providing a ThreadStarting event.</summary>
  	/// <remarks>
  	/// This class is a decorator for the Thread class and thus a 
  	/// drop-in replacement, except that only the most common methods and
  	/// properties (both static and non-static) are provided.
  	/// <para/>
  	/// .NET itself has no support whatsoever from inheriting thread-local 
  	/// variables. Not only are thread locals not inherited from the parent
  	/// thread, .NET fires no event when a thread starts and a child thread
  	/// cannot get the thread ID of the thread that created it.
  	/// <para/>
  	/// ThreadEx helps work around this problem by automatically propagating
  	/// <see cref="ThreadLocalVariable{T}"/> values, and providing the 
  	/// <see cref="ThreadStarting"/> event, which blocks the parent thread but
  	/// is called in the child thread. This only works if you use <see cref="ThreadEx"/>
  	/// to start the child thread; when using other mechanisms such as
  	/// <see cref="System.Threading.Tasks.Task"/>, it is possible to copy thread-
  	/// local variables from the parent thread using code like this:
  	/// <code>
  	/// int parentThreadId = Thread.CurrentThread.ManagedThreadId;
  	/// var task = System.Threading.Tasks.Task.Factory.StartNew(() => {
  	///		using (ThreadEx.PropagateVariables(parentThreadId))
  	///			DoSomethingOnChildThread();
  	///	});
  	///	task.Wait();
  	/// </code>
  	/// Be careful, however: you should guarantee that, while you copy the 
  	/// variables, the parent thread is blocked, or that the parent thread will not 
  	/// modify any of them (which may be difficult since variables might exist that
  	/// you are unaware of, that you do not control).
  	/// <para/>
  	/// TLV (thread-local variable) inheritance is needed to use the 
  	/// <a href="http://www.codeproject.com/Articles/101411/DI-and-Pervasive-services">
  	/// Ambient Service Pattern</a>
  	/// </remarks>
  	public class ThreadEx
  	{
  		protected Thread _parent; // set by Start()
  		protected Thread _thread; // underlying thread
  		protected ThreadStart _ts1;
  		protected ParameterizedThreadStart _ts2;
  		protected int _startState = 0;
  		[ThreadStatic]
  		static bool _areThreadVarsInitialized;
  
  		protected internal static List<WeakReference<ThreadLocalVariableBase>> _TLVs = new List<WeakReference<ThreadLocalVariableBase>>();
  
  		/// <summary>
  		/// This event is called in the context of a newly-started thread, provided
  		/// that the thread is started by the Start() method of this class (rather
  		/// than Thread.Start()).
  		/// </summary>
  		/// <remarks>The Start() method blocks until this event completes.</remarks>
  		public static event EventHandler<ThreadStartEventArgs> ThreadStarting;
  
  		/// <summary>
  		/// This event is called when a thread is stopping, if the thread is stopping
  		/// gracefully and provided that it was started by the Start() method of this 
  		/// class (rather than Thread.Start()).
  		/// </summary>
  		public static event EventHandler<ThreadStartEventArgs> ThreadStopping;
  
  		public ThreadEx(ParameterizedThreadStart start)
  			{ _thread = new Thread(ThreadStart); _ts2 = start; }
  		public ThreadEx(ThreadStart start)
  			{ _thread = new Thread(ThreadStart); _ts1 = start; }
  		public ThreadEx(ParameterizedThreadStart start, int maxStackSize)
  			{ _thread = new Thread(ThreadStart, maxStackSize); _ts2 = start; }
  		public ThreadEx(ThreadStart start, int maxStackSize)
  			{ _thread = new Thread(ThreadStart, maxStackSize); _ts1 = start; }		
  
  		/// <summary>
  		/// Causes the operating system to change the state of the current instance to
  		/// System.Threading.ThreadState.Running.
  		/// </summary>
  		public void Start() { Start(null); }
  
  		/// <summary>
  		/// Causes the operating system to change the state of the current instance to
  		/// System.Threading.ThreadState.Running. Start() does not return until the
  		/// ThreadStarted event is handled.
  		/// </summary><remarks>
  		/// Once the thread terminates, it CANNOT be restarted with another call to Start.
  		/// </remarks>
  		public virtual void Start(object parameter)
  		{
  			if (Interlocked.CompareExchange(ref _startState, 1, 0) != 0)
  				throw new ThreadStateException("The thread has already been started.");
  
  			Debug.Assert(_parent == null);
  			_parent = Thread.CurrentThread;
  
  			// (In case this is Compact Framework, can't use ParameterizedThreadStart)
  			_startParameter = parameter;
  			_thread.Start();
  				
  			while(_startState == 1)
  				Thread.Sleep(0);
  		}
  
  		private object _startParameter;
  		protected virtual void ThreadStart()
  		{
  			object parameter = _startParameter;
  			_startParameter = null;
  			Debug.Assert(_thread == Thread.CurrentThread);
  
  			try {
  				// Inherit thread-local variables from parent
  				InheritThreadLocalVars(_parent.ManagedThreadId);
  
  				// Note that Start() is still running in the parent thread
  				if (ThreadStarting != null)
  					ThreadStarting(this, new ThreadStartEventArgs(_parent, this));
  
  				_startState = 2; // allow parent thread to continue
  
  				if (_ts2 != null)
  					_ts2(parameter);
  				else
  					_ts1();
  			} finally {
  				_startState = 3; // ensure parent thread continues
  
  				if (ThreadStopping != null)
  					ThreadStopping(this, new ThreadStartEventArgs(_parent, this));
  
  				DeinitThreadLocalVars();
  			}
  		}
  
  		static bool InheritThreadLocalVars(int parentThreadId)
  		{
  			int threadId;
  			if (!_areThreadVarsInitialized && (threadId = Thread.CurrentThread.ManagedThreadId) != parentThreadId) {
  				_areThreadVarsInitialized = true;
  				for (int i = 0; i < _TLVs.Count; i++) {
  					ThreadLocalVariableBase v = _TLVs[i].Target();
  					if (v != null)
  						v.Propagate(parentThreadId, threadId);
  				}
  				return true;
  			}
  			return false;
  		}
  		static void DeinitThreadLocalVars()
  		{
  			// Notify thread-local variables of termination
  			for (int i = 0; i < _TLVs.Count; i++) {
  				ThreadLocalVariableBase v = _TLVs[i].Target();
  				if (v != null)
  					v.Terminate(Thread.CurrentThread.ManagedThreadId);
  			}
  		}
  		/// <summary>See <see cref="PropagateVariables"/> for more information.</summary>
  		public struct ThreadDestructor : IDisposable
  		{
  			bool _destroyNeeded;
  			public ThreadDestructor(bool destroyNeeded) { _destroyNeeded = destroyNeeded; }
  			public void Dispose() { if (_destroyNeeded) { DeinitThreadLocalVars(); _destroyNeeded = false; } }
  		}
  
  		/// <summary>
  		/// Manually initializes <see cref="ThreadLocalVariable{T}"/> objects in a
  		/// thread that may not have been started via ThreadEx, propagating values
  		/// from the parent thread. Returns an object for uninitializing the thread.
  		/// </summary>
  		/// <param name="parentThreadId">Id of parent thread. The .NET framework
  		/// does not make this information available so you must somehow pass this 
  		/// value manually from the parent thread to the child thread.</param>
  		/// <returns>An object to be disposed at the end of the thread. This method
  		/// can be called in a using statement so that this happens automatically:
  		/// <c>using(ThreadEx.PropagateVariables(parentThreadId)) { ... }</c>. It is
  		/// important to dispose the returned object so that thread-local values can
  		/// be released to prevent a memory leak.
  		/// </returns>
  		/// <remarks>It is safe to call this method if the thread has already been
  		/// initialized. In that case, the thread will not be initialized a second 
  		/// time, and the returned value will do nothing when it is disposed.
  		/// <para/>
  		/// Be careful with this method: you should guarantee that, while you copy the 
  		/// variables, the parent thread is blocked, or that the parent thread will not 
  		/// modify any of them during the copying process (which may be difficult 
  		/// since variables might exist that you are unaware of, that you do not 
  		/// control).
  		/// </remarks>
  		public static ThreadDestructor PropagateVariables(int parentThreadId)
  		{
  			return new ThreadDestructor(InheritThreadLocalVars(parentThreadId));
  		}
  
  		/// <summary>
  		/// Gets the currently running thread.
  		/// </summary>
  		public static Thread CurrentThread { get { return Thread.CurrentThread; } }
  		/// <summary>
  		/// Gets or sets a value indicating whether or not a thread is a background thread.
  		/// </summary>
  		public bool IsBackground { get { return _thread.IsBackground; } set { _thread.IsBackground = value; } }
  		/// <summary>
  		/// Gets a unique identifier for the current managed thread.
  		/// </summary>
  		public int ManagedThreadId { get { return _thread.ManagedThreadId; } }
  		/// <summary>
  		/// Gets or sets the name of the thread.
  		/// </summary>
  		public string Name { get { return _thread.Name; } set { _thread.Name = value; } }
  		/// <summary>
  		/// Gets or sets a value indicating the scheduling priority of a thread.
  		/// </summary>
  		public ThreadPriority Priority { get { return _thread.Priority; } set { _thread.Priority = value; } }
  		#if !CompactFramework
  		/// <summary>
  		/// Gets a value containing the states of the current thread.
  		/// </summary>
  		public System.Threading.ThreadState ThreadState { get { return _thread.ThreadState; } }
  		#endif
  		/// <summary>
  		/// Raises a System.Threading.ThreadAbortException in the thread on which it
  		/// is invoked, to begin the process of terminating the thread while also providing
  		/// exception information about the thread termination. Calling this method usually
  		/// terminates the thread.
  		/// </summary>
  		public void Abort(object stateInfo) { _thread.Abort(stateInfo); }
  		/// <inheritdoc cref="Abort()"/>
  		public void Abort() { _thread.Abort(); }
  		/// <summary>
  		/// Returns the current domain in which the current thread is running.
  		/// </summary>
  		public static AppDomain GetDomain() { return Thread.GetDomain(); }
  		/// <summary>
  		/// Returns a hash code for the current thread.
  		/// </summary>
  		public override int GetHashCode() { return _thread.GetHashCode(); }
  		/// <summary>
  		/// Blocks the calling thread until a thread terminates, while continuing to
  		/// perform standard COM and SendMessage pumping.
  		/// </summary>
  		public void Join() { _thread.Join(); }
  		/// <summary>
  		/// Blocks the calling thread until a thread terminates or the specified time 
  		/// elapses, while continuing to perform standard COM and SendMessage pumping. 
  		/// </summary>
  		public bool Join(int milliseconds) { return _thread.Join(milliseconds); }
  		#if !CompactFramework
  		public bool Join(TimeSpan timeout) { return _thread.Join(timeout); }
  		#endif
  		/// <summary>
  		/// Suspends the current thread for a specified time.
  		/// </summary>
  		public static void Sleep(int millisecondsTimeout) { Thread.Sleep(millisecondsTimeout); }
  
  		public Thread Thread { get { return _thread; } }
  		public Thread ParentThread { get { return _parent; } }
  
  		#if !CompactFramework
  		public bool IsAlive { 
  			get { 
  				System.Threading.ThreadState t = ThreadState;
  				return t != System.Threading.ThreadState.Stopped &&
  				       t != System.Threading.ThreadState.Unstarted &&
  				       t != System.Threading.ThreadState.Aborted;
  			}
  		}
  		#endif
  
  		internal static void RegisterTLV(ThreadLocalVariableBase tlv)
  		{
  			lock(_TLVs) {
  				for (int i = 0; i < _TLVs.Count; i++)
  
gt: 					if (!_TLVs[i].IsAlive()) {