[corlib] Improve flow of ExecutionContext (few tests taken from https://github.com...
[mono.git] / mcs / class / corlib / System.Threading / ExecutionContext.cs
index ce55788e0ae2e5a8b57b8585c489e32716857a23..5718bbfc23d4c4e5c1f9067cdebe4ca14956a5f7 100644 (file)
@@ -4,8 +4,10 @@
 // Authors:
 //     Lluis Sanchez (lluis@novell.com)
 //     Sebastien Pouliot  <sebastien@ximian.com>
+//  Marek Safar (marek.safar@gmail.com)
 //
 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2014 Xamarin Inc (http://www.xamarin.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -32,6 +34,7 @@ using System.Runtime.Serialization;
 using System.Security;
 using System.Security.Permissions;
 using System.Runtime.Remoting.Messaging;
+using System.Collections.Generic;
 
 namespace System.Threading {
        [Serializable]
@@ -46,17 +49,21 @@ namespace System.Threading {
                private LogicalCallContext _lcc;
                private bool _suppressFlow;
                private bool _capture;
+               Dictionary<string, object> local_data;
 
                internal ExecutionContext ()
                {
                }
 
-               internal ExecutionContext (ExecutionContext ec)
+               private ExecutionContext (ExecutionContext ec)
                {
 #if !MOBILE
                        if (ec._sc != null)
                                _sc = new SecurityContext (ec._sc);
 #endif
+                       if (ec._lcc != null)
+                               _lcc = (LogicalCallContext) ec._lcc.Clone ();
+
                        _suppressFlow = ec._suppressFlow;
                        _capture = true;
                }
@@ -69,24 +76,23 @@ namespace System.Threading {
 
                public static ExecutionContext Capture ()
                {
-                       return Capture (true);
+                       return Capture (true, false);
                }
                
-               internal static ExecutionContext Capture (bool captureSyncContext)
+               internal static ExecutionContext Capture (bool captureSyncContext, bool nullOnEmpty)
                {
-                       ExecutionContext ec = Thread.CurrentThread.ExecutionContext;
+                       ExecutionContext ec = Current;
                        if (ec.FlowSuppressed)
                                return null;
 
+                       if (nullOnEmpty && ec._sc == null && (ec._lcc == null || !ec._lcc.HasInfo))
+                               return null;
+
                        ExecutionContext capture = new ExecutionContext (ec);
 #if !MOBILE
                        if (SecurityManager.SecurityEnabled)
                                capture.SecurityContext = SecurityContext.Capture ();
 #endif
-
-#if !MONOTOUCH
-                       capture.LogicalCallContext = CallContext.CreateLogicalCallContext (false);
-#endif
                        return capture;
                }
                
@@ -122,7 +128,7 @@ namespace System.Threading {
                internal LogicalCallContext LogicalCallContext {
                        get {
                                if (_lcc == null)
-                                       return new LogicalCallContext ();
+                                       _lcc = new LogicalCallContext ();
                                return _lcc;
                        }
                        set {
@@ -130,6 +136,17 @@ namespace System.Threading {
                        }
                }
 
+               internal Dictionary<string, object> DataStore {
+                       get {
+                               if (local_data == null)
+                                       local_data = new Dictionary<string, object> ();
+                               return local_data;
+                       }
+                       set {
+                               local_data = value;
+                       }
+               }
+
 #if !MOBILE
                internal SecurityContext SecurityContext {
                        get {
@@ -146,25 +163,20 @@ namespace System.Threading {
                        set { _suppressFlow = value; }
                }
 
-               // Note: Previous to version 2.0 only the CompressedStack and (sometimes!) the WindowsIdentity
-               // were propagated to new threads. This is why ExecutionContext is internal in before NET_2_0.
-               // It also means that all newer context classes should be here (i.e. inside the #if NET_2_0).
-
                public static bool IsFlowSuppressed ()
                {
-                       return Thread.CurrentThread.ExecutionContext.FlowSuppressed;
+                       return Current.FlowSuppressed;
                }
 
                public static void RestoreFlow ()
                {
-                       ExecutionContext ec = Thread.CurrentThread.ExecutionContext;
+                       ExecutionContext ec = Current;
                        if (!ec.FlowSuppressed)
                                throw new InvalidOperationException ();
 
                        ec.FlowSuppressed = false;
                }
 
-               [MonoTODO ("only the SecurityContext is considered")]
                [SecurityPermission (SecurityAction.LinkDemand, Infrastructure = true)]
                public static void Run (ExecutionContext executionContext, ContextCallback callback, object state)
                {
@@ -173,22 +185,13 @@ namespace System.Threading {
                                        "Null ExecutionContext"));
                        }
 
-#if MOBILE
-                       callback (state);
-#else
-                       // FIXME: supporting more than one context should be done with executionContextSwitcher
-                       // and will requires a rewrite of this method
-                       var callContextCallBack = new ContextCallback (new Action<object> ((ostate) => {
-                               var originalCallContext = CallContext.CreateLogicalCallContext (true);
-                               try {
-                                       CallContext.SetCurrentCallContext (executionContext.LogicalCallContext);
-                                       callback (ostate);
-                               } finally {
-                                       CallContext.SetCurrentCallContext (originalCallContext);
-                               }
-                       }));
-                       SecurityContext.Run (executionContext.SecurityContext, callContextCallBack, state);
-#endif
+                       var prev = Current;
+                       try {
+                               Thread.CurrentThread.ExecutionContext = executionContext;
+                               callback (state);
+                       } finally {
+                               Thread.CurrentThread.ExecutionContext = prev;
+                       }
                }
 
                public static AsyncFlowControl SuppressFlow ()
@@ -197,5 +200,33 @@ namespace System.Threading {
                        t.ExecutionContext.FlowSuppressed = true;
                        return new AsyncFlowControl (t, AsyncFlowControlType.Execution);
                }
+
+               internal static LogicalCallContext CreateLogicalCallContext (bool createEmpty)
+               {
+                       var lcc = Current._lcc;
+                       if (lcc == null) {
+                               if (createEmpty)
+                                       lcc = new LogicalCallContext ();
+
+                               return lcc;
+                       }
+
+                       return (LogicalCallContext) lcc.Clone ();
+               }
+
+               internal void FreeNamedDataSlot (string name)
+               {
+                       if (_lcc != null)
+                               _lcc.FreeNamedDataSlot (name);
+
+                       if (local_data != null)
+                               local_data.Remove (name);
+               }
+
+               internal static ExecutionContext Current {
+                       get {
+                               return Thread.CurrentThread.ExecutionContext;
+                       }
+               }
        }
 }
\ No newline at end of file