2 // System.Runtime.Remoting.Contexts.Context..cs
5 // Miguel de Icaza (miguel@ximian.com)
6 // Lluis Sanchez Gual (lluis@ideary.com)
9 // (C) Ximian, Inc. http://www.ximian.com
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Collections;
36 using System.Collections.Generic;
37 using System.Threading;
38 using System.Runtime.Remoting;
39 using System.Runtime.Remoting.Proxies;
40 using System.Runtime.Remoting.Activation;
41 using System.Runtime.Remoting.Messaging;
42 using System.Runtime.Remoting.Lifetime;
43 using System.Runtime.CompilerServices;
44 using System.Runtime.InteropServices;
47 namespace System.Runtime.Remoting.Contexts {
49 [System.Runtime.InteropServices.ComVisible (true)]
50 [StructLayout (LayoutKind.Sequential)]
53 #pragma warning disable 169, 414
54 #region Sync with domain-internals.h
57 UIntPtr static_data; /* GC-tracked */
60 #pragma warning restore 169, 414
62 // Name is significant; used by the runtime.
64 static object[] local_slots;
66 // Default server context sink chain
67 static IMessageSink default_server_context_sink;
69 // The sink chain that has to be used by all calls entering the context
70 IMessageSink server_context_sink_chain = null;
72 // The sink chain that has to be used by all calls exiting the context
73 IMessageSink client_context_sink_chain = null;
75 List<IContextProperty> context_properties;
78 static int global_count;
80 volatile LocalDataStoreHolder _localDataStore;
82 static LocalDataStoreMgr _localDataStoreMgr = new LocalDataStoreMgr();
84 static DynamicPropertyCollection global_dynamic_properties;
85 DynamicPropertyCollection context_dynamic_properties;
86 ContextCallbackObject callback_object = null;
88 [MethodImpl (MethodImplOptions.InternalCall)]
89 extern static void RegisterContext (Context ctx);
91 [MethodImpl (MethodImplOptions.InternalCall)]
92 extern static void ReleaseContext (Context ctx);
96 domain_id = Thread.GetDomainID();
97 context_id = Interlocked.Increment (ref global_count);
99 RegisterContext (this);
104 ReleaseContext (this);
107 public static Context DefaultContext {
109 return AppDomain.InternalGetDefaultContext ();
113 public virtual int ContextID {
119 public virtual IContextProperty[] ContextProperties
123 if (context_properties == null)
124 return new IContextProperty[0];
126 return context_properties.ToArray ();
130 internal bool IsDefaultContext
132 get { return context_id == 0; }
135 internal bool NeedsContextSink
138 return context_id != 0 ||
139 (global_dynamic_properties != null && global_dynamic_properties.HasProperties) ||
140 (context_dynamic_properties != null && context_dynamic_properties.HasProperties);
144 public static bool RegisterDynamicProperty(IDynamicProperty prop, ContextBoundObject obj, Context ctx)
146 DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
147 return col.RegisterDynamicProperty (prop);
150 public static bool UnregisterDynamicProperty(string name, ContextBoundObject obj, Context ctx)
152 DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
153 return col.UnregisterDynamicProperty (name);
156 static DynamicPropertyCollection GetDynamicPropertyCollection(ContextBoundObject obj, Context ctx)
158 if (ctx == null && obj != null)
160 if (RemotingServices.IsTransparentProxy(obj))
162 RealProxy rp = RemotingServices.GetRealProxy (obj);
163 return rp.ObjectIdentity.ClientDynamicProperties;
168 return obj.ObjectIdentity.ServerDynamicProperties;
170 throw new NotSupportedException ();
174 else if (ctx != null && obj == null)
176 if (ctx.context_dynamic_properties == null) ctx.context_dynamic_properties = new DynamicPropertyCollection ();
177 return ctx.context_dynamic_properties;
179 else if (ctx == null && obj == null)
181 if (global_dynamic_properties == null) global_dynamic_properties = new DynamicPropertyCollection ();
182 return global_dynamic_properties;
185 throw new ArgumentException ("Either obj or ctx must be null");
188 internal static void NotifyGlobalDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
190 if (global_dynamic_properties != null && global_dynamic_properties.HasProperties)
191 global_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
194 internal static bool HasGlobalDynamicSinks
196 get { return (global_dynamic_properties != null && global_dynamic_properties.HasProperties); }
199 internal void NotifyDynamicSinks (bool start, IMessage req_msg, bool client_site, bool async)
201 if (context_dynamic_properties != null && context_dynamic_properties.HasProperties)
202 context_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
205 internal bool HasDynamicSinks
207 get { return (context_dynamic_properties != null && context_dynamic_properties.HasProperties); }
210 internal bool HasExitSinks
214 // Needs to go through the client context sink if there are custom
215 // client context or dynamic sinks.
217 return ( !(GetClientContextSinkChain() is ClientContextTerminatorSink) || HasDynamicSinks || HasGlobalDynamicSinks);
221 public virtual IContextProperty GetProperty (string name)
223 if (context_properties == null)
226 foreach (IContextProperty p in context_properties)
233 public virtual void SetProperty (IContextProperty prop)
236 throw new ArgumentNullException ("IContextProperty");
237 if (this == DefaultContext)
238 throw new InvalidOperationException ("Can not add properties to " +
241 // throw new InvalidOperationException ("Context is Frozen");
243 if (context_properties == null)
244 context_properties = new List<IContextProperty> ();
246 context_properties.Add (prop);
249 public virtual void Freeze ()
251 if (context_properties != null)
253 foreach (IContextProperty prop in context_properties)
258 public override string ToString()
260 return "ContextID: " + context_id;
263 internal IMessageSink GetServerContextSinkChain()
265 if (server_context_sink_chain == null)
267 if (default_server_context_sink == null)
268 default_server_context_sink = new ServerContextTerminatorSink();
270 server_context_sink_chain = default_server_context_sink;
272 if (context_properties != null) {
273 // Enumerate in reverse order
274 for (int n = context_properties.Count-1; n>=0; n--) {
275 IContributeServerContextSink contributor = context_properties[n] as IContributeServerContextSink;
276 if (contributor != null)
277 server_context_sink_chain = contributor.GetServerContextSink (server_context_sink_chain);
281 return server_context_sink_chain;
284 internal IMessageSink GetClientContextSinkChain()
286 if (client_context_sink_chain == null)
288 client_context_sink_chain = new ClientContextTerminatorSink (this);
290 if (context_properties != null) {
291 foreach (IContextProperty prop in context_properties) {
292 IContributeClientContextSink contributor = prop as IContributeClientContextSink;
293 if (contributor != null)
294 client_context_sink_chain = contributor.GetClientContextSink (client_context_sink_chain);
298 return client_context_sink_chain;
301 internal IMessageSink CreateServerObjectSinkChain (MarshalByRefObject obj, bool forceInternalExecute)
303 IMessageSink objectSink = new StackBuilderSink (obj, forceInternalExecute);
304 objectSink = new ServerObjectTerminatorSink (objectSink);
305 objectSink = new Lifetime.LeaseSink (objectSink);
307 if (context_properties != null)
309 // Contribute object sinks in reverse order
310 for (int n = context_properties.Count-1; n >= 0; n--)
312 IContextProperty prop = (IContextProperty) context_properties[n];
313 IContributeObjectSink contributor = prop as IContributeObjectSink;
314 if (contributor != null)
315 objectSink = contributor.GetObjectSink (obj, objectSink);
321 internal IMessageSink CreateEnvoySink (MarshalByRefObject serverObject)
323 IMessageSink sink = EnvoyTerminatorSink.Instance;
324 if (context_properties != null)
326 foreach (IContextProperty prop in context_properties)
328 IContributeEnvoySink contributor = prop as IContributeEnvoySink;
329 if (contributor != null)
330 sink = contributor.GetEnvoySink (serverObject, sink);
336 internal static Context SwitchToContext (Context newContext)
338 return AppDomain.InternalSetContext (newContext);
341 internal static Context CreateNewContext (IConstructionCallMessage msg)
343 // Create the new context
345 Context newContext = new Context();
347 foreach (IContextProperty prop in msg.ContextProperties)
349 if (newContext.GetProperty (prop.Name) == null)
350 newContext.SetProperty (prop);
355 // Ask each context property whether the new context is OK
357 foreach (IContextProperty prop in msg.ContextProperties)
358 if (!prop.IsNewContextOK (newContext))
359 throw new RemotingException("A context property did not approve the candidate context for activating the object");
364 public void DoCallBack (CrossContextDelegate deleg)
368 if (callback_object == null) {
369 Context oldContext = Context.SwitchToContext (this);
370 callback_object = new ContextCallbackObject ();
371 Context.SwitchToContext (oldContext);
375 callback_object.DoCallBack (deleg);
378 private LocalDataStore MyLocalStore
382 if (_localDataStore == null)
384 // It's OK to lock the manager here because it is going to lock
386 lock (_localDataStoreMgr)
388 if (_localDataStore == null)
390 // The local store has not yet been created for this thread.
391 _localDataStore = _localDataStoreMgr.CreateLocalDataStore();
395 return _localDataStore.Store;
399 public static LocalDataStoreSlot AllocateDataSlot ()
401 return _localDataStoreMgr.AllocateDataSlot ();
404 public static LocalDataStoreSlot AllocateNamedDataSlot (string name)
406 return _localDataStoreMgr.AllocateNamedDataSlot (name);
409 public static void FreeNamedDataSlot (string name)
411 _localDataStoreMgr.FreeNamedDataSlot (name);
414 public static LocalDataStoreSlot GetNamedDataSlot (string name)
416 return _localDataStoreMgr.GetNamedDataSlot (name);
419 public static object GetData (LocalDataStoreSlot slot)
421 return Thread.CurrentContext.MyLocalStore.GetData (slot);
424 public static void SetData (LocalDataStoreSlot slot, object data)
426 Thread.CurrentContext.MyLocalStore.SetData (slot, data);
430 class DynamicPropertyCollection
432 ArrayList _properties = new ArrayList();
434 class DynamicPropertyReg
436 public IDynamicProperty Property;
437 public IDynamicMessageSink Sink;
440 public bool HasProperties
442 get { return _properties.Count > 0; }
445 public bool RegisterDynamicProperty(IDynamicProperty prop)
449 if (FindProperty (prop.Name) != -1)
450 throw new InvalidOperationException ("Another property by this name already exists");
452 // Make a copy, do not interfere with threads running dynamic sinks
453 ArrayList newProps = new ArrayList (_properties);
455 DynamicPropertyReg reg = new DynamicPropertyReg();
457 IContributeDynamicSink contributor = prop as IContributeDynamicSink;
458 if (contributor != null) reg.Sink = contributor.GetDynamicSink ();
461 _properties = newProps;
463 return true; // When should be false?
467 public bool UnregisterDynamicProperty(string name)
471 int i = FindProperty (name);
472 if (i == -1) throw new RemotingException ("A property with the name " + name + " was not found");
474 _properties.RemoveAt (i);
475 return true; // When should be false?
479 public void NotifyMessage (bool start, IMessage msg, bool client_site, bool async)
481 ArrayList props = _properties;
484 foreach (DynamicPropertyReg reg in props)
485 if (reg.Sink != null) reg.Sink.ProcessMessageStart (msg, client_site, async);
489 foreach (DynamicPropertyReg reg in props)
490 if (reg.Sink != null) reg.Sink.ProcessMessageFinish (msg, client_site, async);
494 int FindProperty (string name)
496 for (int n=0; n<_properties.Count; n++)
497 if (((DynamicPropertyReg)_properties[n]).Property.Name == name)
503 class ContextCallbackObject: ContextBoundObject
505 public void DoCallBack (CrossContextDelegate deleg)