[Socket] Use type specific read and write queue for SocketAsyncWorker
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Contexts / Context.cs
1 //
2 // System.Runtime.Remoting.Contexts.Context..cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Lluis Sanchez Gual (lluis@ideary.com)
7 //   Patrik Torstensson
8 //
9 // (C) Ximian, Inc.  http://www.ximian.com
10 //
11
12 //
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 //
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:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
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.
33 //
34
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.InteropServices;
44
45
46 namespace System.Runtime.Remoting.Contexts {
47
48         [System.Runtime.InteropServices.ComVisible (true)]
49         [StructLayout (LayoutKind.Sequential)]
50         public class Context 
51         {
52 #pragma warning disable 169, 414
53                 #region Sync with domain-internals.h
54                 int domain_id;
55                 int context_id;
56                 UIntPtr static_data; /* GC-tracked */
57                 #endregion
58 #pragma warning restore 169, 414
59
60                 // Default server context sink chain
61                 static IMessageSink default_server_context_sink;
62
63                 // The sink chain that has to be used by all calls entering the context
64                 IMessageSink server_context_sink_chain = null;
65
66                 // The sink chain that has to be used by all calls exiting the context
67                 IMessageSink client_context_sink_chain = null;
68
69                 object[] datastore;
70                 List<IContextProperty> context_properties;
71 //              bool frozen;
72                 
73                 static int global_count;
74
75                 /* Wrap this in a nested class so its not constructed during shutdown */
76                 class NamedSlots {
77                         public static Hashtable namedSlots = new Hashtable ();
78                 }
79
80                 static DynamicPropertyCollection global_dynamic_properties;
81                 DynamicPropertyCollection context_dynamic_properties;
82                 ContextCallbackObject callback_object = null;
83                 
84                 public Context ()
85                 {
86                         domain_id = Thread.GetDomainID();
87                         context_id = 1 + global_count++;
88                 }
89
90                 ~Context ()
91                 {
92                 }
93
94                 public static Context DefaultContext {
95                         get {
96                                 return AppDomain.InternalGetDefaultContext ();
97                         }
98                 }
99
100                 public virtual int ContextID {
101                         get {
102                                 return context_id;
103                         }
104                 }
105
106                 public virtual IContextProperty[] ContextProperties
107                 {
108                         get 
109                         {
110                                 if (context_properties == null)
111                                         return new IContextProperty[0];
112                                 
113                                 return context_properties.ToArray ();
114                         }
115                 }
116                 
117                 internal bool IsDefaultContext
118                 {
119                         get { return context_id == 0; }
120                 }
121
122                 internal bool NeedsContextSink
123                 {
124                         get {
125                                 return context_id != 0 || 
126                                         (global_dynamic_properties != null && global_dynamic_properties.HasProperties) || 
127                                         (context_dynamic_properties != null && context_dynamic_properties.HasProperties);
128                         }
129                 }
130
131                 public static bool RegisterDynamicProperty(IDynamicProperty prop, ContextBoundObject obj, Context ctx)
132                 {
133                         DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
134                         return col.RegisterDynamicProperty (prop);
135                 }
136
137                 public static bool UnregisterDynamicProperty(string name, ContextBoundObject obj, Context ctx)
138                 {
139                         DynamicPropertyCollection col = GetDynamicPropertyCollection (obj, ctx);
140                         return col.UnregisterDynamicProperty (name);
141                 }
142                 
143                 static DynamicPropertyCollection GetDynamicPropertyCollection(ContextBoundObject obj, Context ctx)
144                 {
145                         if (ctx == null && obj != null)
146                         {
147                                 if (RemotingServices.IsTransparentProxy(obj))
148                                 {
149                                         RealProxy rp = RemotingServices.GetRealProxy (obj);
150                                         return rp.ObjectIdentity.ClientDynamicProperties;
151                                 }
152                                 else
153                                         return obj.ObjectIdentity.ServerDynamicProperties;
154                         }
155                         else if (ctx != null && obj == null)
156                         {
157                                 if (ctx.context_dynamic_properties == null) ctx.context_dynamic_properties = new DynamicPropertyCollection ();
158                                 return ctx.context_dynamic_properties;
159                         }
160                         else if (ctx == null && obj == null)
161                         {
162                                 if (global_dynamic_properties == null) global_dynamic_properties = new DynamicPropertyCollection ();
163                                 return global_dynamic_properties;
164                         }
165                         else
166                                 throw new ArgumentException ("Either obj or ctx must be null");
167                 }
168                 
169                 internal static void NotifyGlobalDynamicSinks  (bool start, IMessage req_msg, bool client_site, bool async)
170                 {
171                         if (global_dynamic_properties != null && global_dynamic_properties.HasProperties) 
172                                 global_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
173                 }
174
175                 internal static bool HasGlobalDynamicSinks
176                 {
177                         get { return (global_dynamic_properties != null && global_dynamic_properties.HasProperties); }
178                 }
179
180                 internal void NotifyDynamicSinks  (bool start, IMessage req_msg, bool client_site, bool async)
181                 {
182                         if (context_dynamic_properties != null && context_dynamic_properties.HasProperties) 
183                                 context_dynamic_properties.NotifyMessage (start, req_msg, client_site, async);
184                 }
185
186                 internal bool HasDynamicSinks
187                 {
188                         get { return (context_dynamic_properties != null && context_dynamic_properties.HasProperties); }
189                 }
190
191                 internal bool HasExitSinks
192                 {
193                         get
194                         {
195                                 // Needs to go through the client context sink if there are custom
196                                 // client context or dynamic sinks.
197
198                                 return ( !(GetClientContextSinkChain() is ClientContextTerminatorSink) || HasDynamicSinks || HasGlobalDynamicSinks);
199                         }
200                 }
201
202                 public virtual IContextProperty GetProperty (string name)
203                 {
204                         if (context_properties == null)
205                                 return null;
206
207                         foreach (IContextProperty p in context_properties)
208                                 if (p.Name == name)
209                                         return p;
210                         
211                         return null;
212                 }
213
214                 public virtual void SetProperty (IContextProperty prop)
215                 {
216                         if (prop == null)
217                                 throw new ArgumentNullException ("IContextProperty");
218                         if (this == DefaultContext)
219                                 throw new InvalidOperationException ("Can not add properties to " +
220                                                                      "default context");
221 //                      if (frozen)
222 //                              throw new InvalidOperationException ("Context is Frozen");
223                         
224                         if (context_properties == null)
225                                 context_properties = new List<IContextProperty> ();
226
227                         context_properties.Add (prop);
228                 }
229
230                 public virtual void Freeze ()
231                 {
232                         if (context_properties != null)
233                         {
234                                 foreach (IContextProperty prop in context_properties)
235                                         prop.Freeze (this);
236                         }
237                 }
238
239                 public override string ToString()
240                 {
241                         return "ContextID: " + context_id;
242                 }
243
244                 internal IMessageSink GetServerContextSinkChain()
245                 {
246                         if (server_context_sink_chain == null)
247                         {
248                                 if (default_server_context_sink == null)
249                                         default_server_context_sink = new ServerContextTerminatorSink();
250
251                                 server_context_sink_chain = default_server_context_sink;
252
253                                 if (context_properties != null) {
254                                         // Enumerate in reverse order
255                                         for (int n = context_properties.Count-1; n>=0; n--) {
256                                                 IContributeServerContextSink contributor = context_properties[n] as IContributeServerContextSink;
257                                                 if (contributor != null)
258                                                         server_context_sink_chain = contributor.GetServerContextSink (server_context_sink_chain);
259                                         }
260                                 }
261                         }
262                         return server_context_sink_chain;
263                 }
264
265                 internal IMessageSink GetClientContextSinkChain()
266                 {
267                         if (client_context_sink_chain == null)
268                         {
269                                 client_context_sink_chain = new ClientContextTerminatorSink (this);
270
271                                 if (context_properties != null) {
272                                         foreach (IContextProperty prop in context_properties) {
273                                                 IContributeClientContextSink contributor = prop as IContributeClientContextSink;
274                                                 if (contributor != null)
275                                                         client_context_sink_chain = contributor.GetClientContextSink (client_context_sink_chain);
276                                         }
277                                 }
278                         }
279                         return client_context_sink_chain;
280                 }
281
282                 internal IMessageSink CreateServerObjectSinkChain (MarshalByRefObject obj, bool forceInternalExecute)
283                 {
284                         IMessageSink objectSink = new StackBuilderSink (obj, forceInternalExecute);
285                         objectSink = new ServerObjectTerminatorSink (objectSink);
286                         objectSink = new Lifetime.LeaseSink (objectSink);
287
288                         if (context_properties != null)
289                         {
290                                 // Contribute object sinks in reverse order
291                                 for (int n = context_properties.Count-1; n >= 0; n--)
292                                 {
293                                         IContextProperty prop = (IContextProperty) context_properties[n];
294                                         IContributeObjectSink contributor = prop as IContributeObjectSink;
295                                         if (contributor != null)
296                                                 objectSink = contributor.GetObjectSink (obj, objectSink);
297                                 }
298                         }
299                         return objectSink;
300                 }
301
302                 internal IMessageSink CreateEnvoySink (MarshalByRefObject serverObject)
303                 {
304                         IMessageSink sink = EnvoyTerminatorSink.Instance;
305                         if (context_properties != null)
306                         {
307                                 foreach (IContextProperty prop in context_properties)
308                                 {
309                                         IContributeEnvoySink contributor = prop as IContributeEnvoySink;
310                                         if (contributor != null)
311                                                 sink = contributor.GetEnvoySink (serverObject, sink);
312                                 }
313                         }
314                         return sink;
315                 }
316
317                 internal static Context SwitchToContext (Context newContext)
318                 {
319                         return AppDomain.InternalSetContext (newContext);
320                 }
321
322                 internal static Context CreateNewContext (IConstructionCallMessage msg)
323                 {
324                         // Create the new context
325
326                         Context newContext = new Context();
327
328                         foreach (IContextProperty prop in msg.ContextProperties)
329                         {
330                                 if (newContext.GetProperty (prop.Name) == null)
331                                         newContext.SetProperty (prop);
332                         }
333                         newContext.Freeze();
334
335
336                         // Ask each context property whether the new context is OK
337
338                         foreach (IContextProperty prop in msg.ContextProperties)
339                                 if (!prop.IsNewContextOK (newContext)) 
340                                         throw new RemotingException("A context property did not approve the candidate context for activating the object");
341
342                         return newContext;
343                 }
344                 
345                 public void DoCallBack (CrossContextDelegate deleg)
346                 {
347                         lock (this)
348                         {
349                                 if (callback_object == null) {
350                                         Context oldContext = Context.SwitchToContext (this);
351                                         callback_object = new ContextCallbackObject ();
352                                         Context.SwitchToContext (oldContext);
353                                 }
354                         }
355                         
356                         callback_object.DoCallBack (deleg);
357                 }
358                 
359                 public static LocalDataStoreSlot AllocateDataSlot ()
360                 {
361                         return new LocalDataStoreSlot (false);
362                 }
363                 
364                 public static LocalDataStoreSlot AllocateNamedDataSlot (string name)
365                 {
366                         lock (NamedSlots.namedSlots.SyncRoot)
367                         {
368                                 LocalDataStoreSlot slot = AllocateDataSlot ();
369                                 NamedSlots.namedSlots.Add (name, slot);
370                                 return slot;
371                         }
372                 }
373                 
374                 public static void FreeNamedDataSlot (string name)
375                 {
376                         lock (NamedSlots.namedSlots.SyncRoot)
377                         {
378                                 NamedSlots.namedSlots.Remove (name);
379                         }
380                 }
381                 
382                 public static object GetData (LocalDataStoreSlot slot)
383                 {
384                         Context ctx = Thread.CurrentContext;
385                         
386                         lock (ctx)
387                         {
388                                 if (ctx.datastore != null && slot.slot < ctx.datastore.Length)
389                                         return ctx.datastore [slot.slot];
390                                 return null;
391                         }
392                 }
393                 
394                 public static LocalDataStoreSlot GetNamedDataSlot (string name)
395                 {
396                         lock (NamedSlots.namedSlots.SyncRoot)
397                         {
398                                 LocalDataStoreSlot slot = NamedSlots.namedSlots [name] as LocalDataStoreSlot;
399                                 if (slot == null) return AllocateNamedDataSlot (name);
400                                 else return slot;
401                         }
402                 }
403                 
404                 public static void SetData (LocalDataStoreSlot slot, object data)
405                 {
406                         Context ctx = Thread.CurrentContext;
407                         lock (ctx)
408                         {
409                                 if (ctx.datastore == null) {
410                                         ctx.datastore = new object [slot.slot + 2];
411                                 } else if (slot.slot >= ctx.datastore.Length) {
412                                         object[] nslots = new object [slot.slot + 2];
413                                         ctx.datastore.CopyTo (nslots, 0);
414                                         ctx.datastore = nslots;
415                                 }
416                                 ctx.datastore [slot.slot] = data;
417                         }
418                 }
419         }
420
421         class DynamicPropertyCollection
422         {
423                 ArrayList _properties = new ArrayList();
424
425                 class DynamicPropertyReg
426                 {
427                         public IDynamicProperty Property;
428                         public IDynamicMessageSink Sink;
429                 }
430
431                 public bool HasProperties
432                 {
433                         get { return _properties.Count > 0; }
434                 }
435
436                 public bool RegisterDynamicProperty(IDynamicProperty prop)
437                 {
438                         lock (this)
439                         {
440                                 if (FindProperty (prop.Name) != -1) 
441                                         throw new InvalidOperationException ("Another property by this name already exists");
442
443                                 // Make a copy, do not interfere with threads running dynamic sinks
444                                 ArrayList newProps = new ArrayList (_properties);
445
446                                 DynamicPropertyReg reg = new DynamicPropertyReg();
447                                 reg.Property = prop;
448                                 IContributeDynamicSink contributor = prop as IContributeDynamicSink;
449                                 if (contributor != null) reg.Sink = contributor.GetDynamicSink ();
450                                 newProps.Add (reg);
451
452                                 _properties = newProps;
453
454                                 return true;    // When should be false?
455                         }
456                 }
457
458                 public bool UnregisterDynamicProperty(string name)
459                 {
460                         lock (this)
461                         {
462                                 int i = FindProperty (name);
463                                 if (i == -1) throw new RemotingException ("A property with the name " + name + " was not found");
464
465                                 _properties.RemoveAt (i);
466                                 return true;    // When should be false?
467                         }
468                 }
469
470                 public void NotifyMessage (bool start, IMessage msg, bool client_site, bool async)
471                 {
472                         ArrayList props = _properties;
473                         if (start)
474                         {
475                                 foreach (DynamicPropertyReg reg in props)
476                                         if (reg.Sink != null) reg.Sink.ProcessMessageStart (msg, client_site, async);
477                         }
478                         else
479                         {
480                                 foreach (DynamicPropertyReg reg in props)
481                                         if (reg.Sink != null) reg.Sink.ProcessMessageFinish (msg, client_site, async);
482                         }
483                 }
484
485                 int FindProperty (string name)
486                 {
487                         for (int n=0; n<_properties.Count; n++)
488                                 if (((DynamicPropertyReg)_properties[n]).Property.Name == name)
489                                         return n;
490                         return -1;
491                 }
492         }
493         
494         class ContextCallbackObject: ContextBoundObject
495         {
496                 public void DoCallBack (CrossContextDelegate deleg)
497                 {
498                 }
499         }
500 }