[corlib] Fixed StringBuilder construction bugs in marshalling caused by changes to...
[mono.git] / mcs / class / corlib / System.Threading / ExecutionContext.cs
1 // 
2 // System.Threading.ExecutionContext.cs
3 //
4 // Authors:
5 //      Lluis Sanchez (lluis@novell.com)
6 //      Sebastien Pouliot  <sebastien@ximian.com>
7 //  Marek Safar (marek.safar@gmail.com)
8 //
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
10 // Copyright (C) 2014 Xamarin Inc (http://www.xamarin.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Runtime.InteropServices;
33 using System.Runtime.Serialization;
34 using System.Security;
35 using System.Security.Permissions;
36 using System.Runtime.Remoting.Messaging;
37 using System.Collections.Generic;
38
39 namespace System.Threading {
40         [Serializable]
41         public sealed partial class ExecutionContext : ISerializable
42            , IDisposable
43         {
44                 internal struct Switcher
45                 {
46                         readonly ExecutionContext ec;
47                         readonly LogicalCallContext _lcc;
48                         readonly bool _suppressFlow;
49                         readonly bool _capture;
50                         readonly Dictionary<string, object> local_data;
51                         readonly bool copy_on_write;
52
53                         public Switcher (ExecutionContext ec)
54                         {
55                                 this.ec = ec;
56                                 this._lcc = ec._lcc;
57                                 this._suppressFlow = ec._suppressFlow;
58                                 this._capture = ec._capture;
59                                 this.local_data = ec.local_data;
60                                 this.copy_on_write = ec.CopyOnWrite;
61                         }
62
63                         public bool IsEmpty {
64                                 get {
65                                         return ec == null;
66                                 }
67                         }
68
69                         public void Restore (ExecutionContext ec)
70                         {
71                                 ec._lcc = this._lcc;
72                                 ec._suppressFlow = this._suppressFlow;
73                                 ec._capture = this._capture;
74                                 ec.local_data = this.local_data;
75                                 ec.CopyOnWrite = this.copy_on_write;
76                         }
77                 }
78
79 #if !MOBILE
80                 private SecurityContext _sc;
81 #endif
82                 private LogicalCallContext _lcc;
83                 private bool _suppressFlow;
84                 private bool _capture;
85                 Dictionary<string, object> local_data;
86
87                 internal ExecutionContext ()
88                 {
89                 }
90
91                 private ExecutionContext (ExecutionContext ec)
92                 {
93                         CloneData (ec);
94
95                         _suppressFlow = ec._suppressFlow;
96                         _capture = true;
97                 }
98
99                 void CloneData (ExecutionContext ec)
100                 {
101 #if !MOBILE
102                         if (ec._sc != null)
103                                 _sc = new SecurityContext (ec._sc);
104 #endif
105                         if (ec._lcc != null)
106                                 _lcc = (LogicalCallContext) ec._lcc.Clone ();
107                 }
108                 
109                 [MonoTODO]
110                 internal ExecutionContext (SerializationInfo info, StreamingContext context)
111                 {
112                         throw new NotImplementedException ();
113                 }
114
115                 public static ExecutionContext Capture ()
116                 {
117                         return Capture (true, false);
118                 }
119                 
120                 internal static ExecutionContext Capture (bool captureSyncContext, bool nullOnEmpty)
121                 {
122                         var thread = Thread.CurrentThread;
123                         if (nullOnEmpty && !thread.HasExecutionContext)
124                                 return null;
125
126                         var ec = thread.ExecutionContext;
127                         if (ec.FlowSuppressed)
128                                 return null;
129
130                         if (nullOnEmpty
131 #if !MOBILE
132                          && ec._sc == null
133 #endif
134                                 && (ec._lcc == null || !ec._lcc.HasInfo))
135                                 return null;
136
137                         ExecutionContext capture = new ExecutionContext (ec);
138 #if !MOBILE
139                         if (SecurityManager.SecurityEnabled)
140                                 capture.SecurityContext = SecurityContext.Capture ();
141 #endif
142                         return capture;
143                 }
144                 
145                 public ExecutionContext CreateCopy ()
146                 {
147                         if (!_capture)
148                                 throw new InvalidOperationException ();
149
150                         return new ExecutionContext (this);
151                 }
152                 
153                 public void Dispose ()
154                 {
155 #if !MOBILE
156                         if (_sc != null)
157                                 _sc.Dispose ();
158 #endif
159                 }
160
161                 [MonoTODO]
162                 [ReflectionPermission (SecurityAction.Demand, MemberAccess = true)]
163                 public void GetObjectData (SerializationInfo info, StreamingContext context)
164                 {
165                         if (info == null)
166                                 throw new ArgumentNullException ("info");
167                         throw new NotImplementedException ();
168                 }
169                 
170                 // internal stuff
171
172                 internal LogicalCallContext LogicalCallContext {
173                         get {
174                                 if (_lcc == null)
175                                         _lcc = new LogicalCallContext ();
176                                 return _lcc;
177                         }
178                         set {
179                                 _lcc = value;
180                         }
181                 }
182
183                 internal Dictionary<string, object> DataStore {
184                         get {
185                                 if (local_data == null)
186                                         local_data = new Dictionary<string, object> ();
187                                 return local_data;
188                         }
189                         set {
190                                 local_data = value;
191                         }
192                 }
193
194 #if !MOBILE
195                 internal SecurityContext SecurityContext {
196                         get {
197                                 if (_sc == null)
198                                         _sc = new SecurityContext ();
199                                 return _sc;
200                         }
201                         set { _sc = value; }
202                 }
203 #endif
204
205                 internal bool FlowSuppressed {
206                         get { return _suppressFlow; }
207                         set { _suppressFlow = value; }
208                 }
209
210                 internal bool CopyOnWrite { get; set; }
211
212                 public static bool IsFlowSuppressed ()
213                 {
214                         return Current.FlowSuppressed;
215                 }
216
217                 public static void RestoreFlow ()
218                 {
219                         ExecutionContext ec = Current;
220                         if (!ec.FlowSuppressed)
221                                 throw new InvalidOperationException ();
222
223                         ec.FlowSuppressed = false;
224                 }
225                 
226                 internal static void Run(ExecutionContext executionContext, ContextCallback callback, Object state, bool preserveSyncCtx)
227                 {
228                         Run (executionContext, callback, state);
229                 }
230
231                 [SecurityPermission (SecurityAction.LinkDemand, Infrastructure = true)]
232                 public static void Run (ExecutionContext executionContext, ContextCallback callback, object state)
233                 {
234                         if (executionContext == null) {
235                                 throw new InvalidOperationException (Locale.GetText (
236                                         "Null ExecutionContext"));
237                         }
238
239                         var prev = Current;
240                         try {
241                                 Thread.CurrentThread.ExecutionContext = executionContext;
242                                 callback (state);
243                         } finally {
244                                 Thread.CurrentThread.ExecutionContext = prev;
245                         }
246                 }
247
248                 public static AsyncFlowControl SuppressFlow ()
249                 {
250                         Thread t = Thread.CurrentThread;
251                         t.ExecutionContext.FlowSuppressed = true;
252                         return new AsyncFlowControl (t, AsyncFlowControlType.Execution);
253                 }
254
255                 internal static LogicalCallContext CreateLogicalCallContext (bool createEmpty)
256                 {
257                         var lcc = Current._lcc;
258                         if (lcc == null) {
259                                 if (createEmpty)
260                                         lcc = new LogicalCallContext ();
261
262                                 return lcc;
263                         }
264
265                         return (LogicalCallContext) lcc.Clone ();
266                 }
267
268                 internal void FreeNamedDataSlot (string name)
269                 {
270                         if (_lcc != null)
271                                 _lcc.FreeNamedDataSlot (name);
272
273                         if (local_data != null)
274                                 local_data.Remove (name);
275                 }
276
277                 internal static ExecutionContext Current {
278                         get {
279                                 return Thread.CurrentThread.ExecutionContext;
280                         }
281                 }
282
283                 internal static ExecutionContext GetCurrentWritable ()
284                 {
285                         var current = Thread.CurrentThread.ExecutionContext;
286                         if (current.CopyOnWrite) {
287                                 current.CopyOnWrite = false;
288                                 current.CloneData (current);
289                         }
290
291                         return current;
292                 }
293         }
294 }