1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 //
5 // ==--==
6 /*============================================================
7 **
8 ** File:    TrackingServices.cs
9 **
10 **
11 ** Purpose: Defines the services for tracking lifetime and other
12 **          operations on objects.
13 **
14 **
15 ===========================================================*/
16 namespace System.Runtime.Remoting.Services {
17     using System.Security.Permissions;
18     using System;
19     using System.Threading;
20     using System.Globalization;
21     using System.Diagnostics.Contracts;
22     using System.Diagnostics.CodeAnalysis;
23 
24 [System.Runtime.InteropServices.ComVisible(true)]
25 public interface ITrackingHandler
26 {
27     // Notify a handler that an object has been marshaled
28     [System.Security.SecurityCritical]  // auto-generated_required
MarshaledObject(Object obj, ObjRef or)29     void MarshaledObject(Object obj, ObjRef or);
30 
31     // Notify a handler that an object has been unmarshaled
32     [System.Security.SecurityCritical]  // auto-generated_required
UnmarshaledObject(Object obj, ObjRef or)33     void UnmarshaledObject(Object obj, ObjRef or);
34 
35     // Notify a handler that an object has been disconnected
36     [System.Security.SecurityCritical]  // auto-generated_required
DisconnectedObject(Object obj)37     void DisconnectedObject(Object obj);
38 }
39 
40 
41 [System.Security.SecurityCritical]  // auto-generated_required
42 [System.Runtime.InteropServices.ComVisible(true)]
43 public class TrackingServices
44 {
45     // Private member variables
46     private static volatile ITrackingHandler[] _Handlers = new ITrackingHandler[0];  // Array of registered tracking handlers
47     private static volatile int _Size = 0;                                           // Number of elements in the array
48 
49     private static Object s_TrackingServicesSyncObject = null;
50 
51     private static Object TrackingServicesSyncObject
52     {
53         get
54         {
55             if (s_TrackingServicesSyncObject == null)
56             {
57                 Object o = new Object();
58                 Interlocked.CompareExchange(ref s_TrackingServicesSyncObject, o, null);
59             }
60             return s_TrackingServicesSyncObject;
61         }
62     }
63 
64     [System.Security.SecurityCritical]  // auto-generated
RegisterTrackingHandler(ITrackingHandler handler)65     public static void RegisterTrackingHandler(ITrackingHandler handler)
66     {
67         // Validate arguments
68         if (null == handler)
69         {
70             throw new ArgumentNullException("handler");
71         }
72         Contract.EndContractBlock();
73 
74         lock (TrackingServicesSyncObject)
75         {
76             // Check to make sure that the handler has not been registered
77             if(-1 == Match(handler))
78             {
79                 // Allocate a new array if necessary
80                 if((null == _Handlers) || (_Size == _Handlers.Length))
81                 {
82                     ITrackingHandler[] temp = new ITrackingHandler[_Size*2+4];
83                     if(null != _Handlers)
84                     {
85                         Array.Copy(_Handlers, temp, _Size);
86                     }
87                     _Handlers = temp;
88                 }
89 
90                 Volatile.Write(ref _Handlers[_Size++], handler);
91             }
92             else
93             {
94                 throw new RemotingException(Environment.GetResourceString("Remoting_TrackingHandlerAlreadyRegistered", "handler"));
95             }
96         }
97     }
98 
99     [System.Security.SecurityCritical]  // auto-generated
UnregisterTrackingHandler(ITrackingHandler handler)100     public static void UnregisterTrackingHandler(ITrackingHandler handler)
101     {
102         // Validate arguments
103         if (null == handler)
104         {
105             throw new ArgumentNullException("handler");
106         }
107         Contract.EndContractBlock();
108 
109         lock (TrackingServicesSyncObject)
110         {
111             // Check to make sure that the channel has been registered
112             int matchingIdx = Match(handler);
113             if(-1 == matchingIdx)
114             {
115                 throw new RemotingException(Environment.GetResourceString("Remoting_HandlerNotRegistered", handler));
116             }
117 
118             // Delete the entry by copying the remaining entries
119             Array.Copy(_Handlers, matchingIdx+1, _Handlers, matchingIdx, _Size-matchingIdx-1);
120             _Size--;
121         }
122     }
123 
124     public static ITrackingHandler[] RegisteredHandlers
125     {
126         [System.Security.SecurityCritical]  // auto-generated
127         get
128         {
129             lock(TrackingServicesSyncObject)
130             {
131                 if(0 == _Size)
132                 {
133                     return new ITrackingHandler[0];
134                 }
135                 else
136                 {
137                     // Copy the array of registered handlers into a new array
138                     // and return
139                     ITrackingHandler[] temp = new ITrackingHandler[_Size];
140                     for(int i = 0; i < _Size; i++)
141                     {
142                         temp[i] = _Handlers[i];
143                     }
144                     return temp;
145                 }
146             }
147         }
148     }
149 
150     // Notify all the handlers that an object has been marshaled
151     [System.Security.SecurityCritical]  // auto-generated
MarshaledObject(Object obj, ObjRef or)152     internal static void MarshaledObject(Object obj, ObjRef or)
153     {
154         try{
155             ITrackingHandler[] temp = _Handlers;
156             for(int i = 0; i < _Size; i++)
157             {
158                 Volatile.Read(ref temp[i]).MarshaledObject(obj, or);
159             }
160         }
161         catch {}
162     }
163 
164     // Notify all the handlers that an object has been unmarshaled
165     [System.Security.SecurityCritical]  // auto-generated
UnmarshaledObject(Object obj, ObjRef or)166     internal static void UnmarshaledObject(Object obj, ObjRef or)
167     {
168         try{
169             ITrackingHandler[] temp = _Handlers;
170             for(int i = 0; i < _Size; i++)
171             {
172                 Volatile.Read(ref temp[i]).UnmarshaledObject(obj, or);
173             }
174         }
175         catch {}
176     }
177 
178     // Notify all the handlers that an object has been disconnected
179     [System.Security.SecurityCritical]  // auto-generated
DisconnectedObject(Object obj)180     internal static void DisconnectedObject(Object obj)
181     {
182         try{
183             ITrackingHandler[] temp = _Handlers;
184             for(int i = 0; i < _Size; i++)
185             {
186                 Volatile.Read(ref temp[i]).DisconnectedObject(obj);
187             }
188         }
189         catch {}
190     }
191 
192     [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety")]
Match(ITrackingHandler handler)193     private static int Match(ITrackingHandler handler)
194     {
195         int idx = -1;
196 
197         for(int i = 0; i < _Size; i++)
198         {
199             if(_Handlers[i] == handler)
200             {
201                 idx = i;
202                 break;
203             }
204         }
205 
206         return idx;
207     }
208 }
209 
210 } // namespace
211