1 // ==++== 2 // 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // 5 // ==--== 6 //+---------------------------------------------------------------------------- 7 // 8 // Microsoft Windows 9 // File: LifetimeServices.cs 10 // 11 // Contents: Used to obtain a lease < 12 13 14 15 // 16 //+---------------------------------------------------------------------------- 17 18 namespace System.Runtime.Remoting.Lifetime 19 20 { 21 using System; 22 using System.Threading; 23 using System.Security; 24 using System.Security.Permissions; 25 using System.Runtime.Remoting.Contexts; 26 using System.Runtime.Remoting.Messaging; 27 using System.Globalization; 28 29 // access needs to be restricted 30 [System.Security.SecurityCritical] // auto-generated_required 31 [System.Runtime.InteropServices.ComVisible(true)] 32 public sealed class LifetimeServices 33 { 34 // Set once boolean 35 private static bool s_isLeaseTime = false; 36 private static bool s_isRenewOnCallTime = false; 37 private static bool s_isSponsorshipTimeout = false; 38 39 // Default values 40 private static long s_leaseTimeTicks = TimeSpan.FromMinutes(5).Ticks; 41 private static long s_renewOnCallTimeTicks = TimeSpan.FromMinutes(2).Ticks; 42 private static long s_sponsorshipTimeoutTicks = TimeSpan.FromMinutes(2).Ticks; 43 private static long s_pollTimeTicks = TimeSpan.FromMilliseconds(10000).Ticks; 44 GetTimeSpan(ref long ticks)45 private static TimeSpan GetTimeSpan(ref long ticks) 46 { 47 return TimeSpan.FromTicks(Volatile.Read(ref ticks)); 48 } 49 SetTimeSpan(ref long ticks, TimeSpan value)50 private static void SetTimeSpan(ref long ticks, TimeSpan value) 51 { 52 Volatile.Write(ref ticks, value.Ticks); 53 } 54 55 // Testing values 56 //private static TimeSpan s_leaseTimeTicks = TimeSpan.FromSeconds(20).Ticks; 57 //private static TimeSpan s_renewOnCallTimeTicks = TimeSpan.FromSeconds(20).Ticks; 58 //private static TimeSpan s_sponsorshipTimeoutTicks = TimeSpan.FromSeconds(20).Ticks; 59 //private static TimeSpan s_pollTimeTicks = TimeSpan.FromMilliseconds(10000).Ticks; 60 61 private static Object s_LifetimeSyncObject = null; 62 63 private static Object LifetimeSyncObject 64 { 65 get 66 { 67 if (s_LifetimeSyncObject == null) 68 { 69 Object o = new Object(); 70 Interlocked.CompareExchange(ref s_LifetimeSyncObject, o, null); 71 } 72 return s_LifetimeSyncObject; 73 } 74 } 75 76 // This should have been a static class, but wasn't as of v3.5. Clearly, this is 77 // broken. We'll keep this in V4 for binary compat, but marked obsolete as error 78 // so migrated source code gets fixed. 79 [Obsolete("Do not create instances of the LifetimeServices class. Call the static methods directly on this type instead", true)] LifetimeServices()80 public LifetimeServices() 81 { 82 // Should be a static type - this exists in V4 for binary compatiblity. 83 } 84 85 // Initial Lease Time span for appdomain 86 public static TimeSpan LeaseTime 87 { 88 get{ return GetTimeSpan(ref s_leaseTimeTicks); } 89 90 [System.Security.SecurityCritical] // auto-generated 91 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)] 92 set 93 { 94 lock(LifetimeSyncObject) 95 { 96 if (s_isLeaseTime) 97 throw new RemotingException(Environment.GetResourceString("Remoting_Lifetime_SetOnce", "LeaseTime")); 98 99 100 SetTimeSpan(ref s_leaseTimeTicks, value); 101 s_isLeaseTime = true; 102 } 103 } 104 105 } 106 107 // Initial renew on call time span for appdomain 108 public static TimeSpan RenewOnCallTime 109 { 110 get{ return GetTimeSpan(ref s_renewOnCallTimeTicks); } 111 [System.Security.SecurityCritical] // auto-generated 112 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)] 113 set 114 { 115 lock(LifetimeSyncObject) 116 { 117 if (s_isRenewOnCallTime) 118 throw new RemotingException(Environment.GetResourceString("Remoting_Lifetime_SetOnce", "RenewOnCallTime")); 119 120 121 SetTimeSpan(ref s_renewOnCallTimeTicks, value); 122 s_isRenewOnCallTime = true; 123 } 124 } 125 126 } 127 128 129 // Initial sponsorshiptimeout for appdomain 130 public static TimeSpan SponsorshipTimeout 131 132 { 133 get{ return GetTimeSpan(ref s_sponsorshipTimeoutTicks); } 134 [System.Security.SecurityCritical] // auto-generated 135 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)] 136 set 137 { 138 lock(LifetimeSyncObject) 139 { 140 if (s_isSponsorshipTimeout) 141 throw new RemotingException(Environment.GetResourceString("Remoting_Lifetime_SetOnce", "SponsorshipTimeout")); 142 SetTimeSpan(ref s_sponsorshipTimeoutTicks, value); 143 s_isSponsorshipTimeout = true; 144 } 145 } 146 147 } 148 149 150 // Initial sponsorshiptimeout for appdomain 151 public static TimeSpan LeaseManagerPollTime 152 153 { 154 get{ return GetTimeSpan(ref s_pollTimeTicks); } 155 [System.Security.SecurityCritical] // auto-generated 156 [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)] 157 set 158 { 159 lock(LifetimeSyncObject) 160 { 161 SetTimeSpan(ref s_pollTimeTicks, value); 162 if (LeaseManager.IsInitialized()) 163 LeaseManager.GetLeaseManager().ChangePollTime(value); 164 } 165 } 166 167 } 168 169 170 171 [System.Security.SecurityCritical] // auto-generated GetLeaseInitial(MarshalByRefObject obj)172 internal static ILease GetLeaseInitial(MarshalByRefObject obj) 173 174 { 175 ILease lease = null; 176 LeaseManager leaseManager = LeaseManager.GetLeaseManager(LeaseManagerPollTime); 177 lease = (ILease)leaseManager.GetLease(obj); 178 if (lease == null) 179 lease = CreateLease(obj); 180 return lease; 181 182 } 183 184 185 [System.Security.SecurityCritical] // auto-generated GetLease(MarshalByRefObject obj)186 internal static ILease GetLease(MarshalByRefObject obj) 187 188 { 189 ILease lease = null; 190 LeaseManager leaseManager = LeaseManager.GetLeaseManager(LeaseManagerPollTime); 191 lease = (ILease)leaseManager.GetLease(obj); 192 return lease; 193 194 } 195 196 197 198 199 //internal static ILease CreateLease(MarshalByRefObject obj, IMessageSink nextSink) 200 201 [System.Security.SecurityCritical] // auto-generated CreateLease(MarshalByRefObject obj)202 internal static ILease CreateLease(MarshalByRefObject obj) 203 204 { 205 return CreateLease(LeaseTime, RenewOnCallTime, SponsorshipTimeout, obj); 206 207 } 208 209 210 [System.Security.SecurityCritical] // auto-generated CreateLease(TimeSpan leaseTime, TimeSpan renewOnCallTime, TimeSpan sponsorshipTimeout, MarshalByRefObject obj )211 internal static ILease CreateLease(TimeSpan leaseTime, 212 TimeSpan renewOnCallTime, 213 TimeSpan sponsorshipTimeout, 214 MarshalByRefObject obj 215 ) 216 217 { 218 // Will create leaseManager if not already created. 219 LeaseManager.GetLeaseManager(LeaseManagerPollTime); 220 return (ILease)(new Lease(leaseTime, renewOnCallTime, sponsorshipTimeout, obj)); 221 222 } 223 224 } 225 226 227 [Serializable] 228 internal class LeaseLifeTimeServiceProperty : IContextProperty, IContributeObjectSink 229 230 { 231 232 public String Name 233 234 { 235 [System.Security.SecurityCritical] // auto-generated 236 get {return "LeaseLifeTimeServiceProperty";} 237 238 } 239 240 241 [System.Security.SecurityCritical] // auto-generated IsNewContextOK(Context newCtx)242 public bool IsNewContextOK(Context newCtx) 243 244 { 245 return true; 246 247 } 248 249 250 [System.Security.SecurityCritical] // auto-generated Freeze(Context newContext)251 public void Freeze(Context newContext) 252 253 { 254 255 } 256 257 258 // Initiates the creation of a lease 259 260 // Creates a sink for invoking a renew on call when an object is created. 261 262 [System.Security.SecurityCritical] // auto-generated GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)263 public IMessageSink GetObjectSink(MarshalByRefObject obj, 264 IMessageSink nextSink) 265 266 { 267 bool fServer; 268 ServerIdentity identity = (ServerIdentity)MarshalByRefObject.GetIdentity(obj, out fServer); 269 BCLDebug.Assert(identity != null, "[LifetimeServices.GetObjectSink] identity != null"); 270 271 // NOTE: Single Call objects do not have a lease associated with it because they last 272 // only for the duration of the call. 273 // Singleton objects on the other hand do have leases associated with them and they can 274 // be garbage collected. 275 if (identity.IsSingleCall()) 276 { 277 BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, no lease SingleCall",obj,", NextSink "+nextSink); 278 return nextSink; 279 } 280 281 282 283 // Create lease. InitializeLifetimeService is a virtual method which can be overridded so that a lease with 284 // object specific properties can be created. 285 Object leaseObj = obj.InitializeLifetimeService(); 286 287 288 BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, return from InitializeLifetimeService obj ",obj,", lease ",leaseObj); 289 290 291 // InitializeLifetimeService can return a lease in one of conditions: 292 // 1) the lease has a null state which specifies that no lease is to be created. 293 // 2) the lease has an initial state which specifies that InitializeLifeTimeService has created a new lease. 294 // 3) the lease has another state which indicates that the lease has already been created and registered. 295 296 297 if (leaseObj == null) 298 { 299 BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, no lease ",obj,", NextSink "+nextSink); 300 return nextSink; 301 } 302 303 if (!(leaseObj is System.Runtime.Remoting.Lifetime.ILease)) 304 throw new RemotingException(Environment.GetResourceString("Remoting_Lifetime_ILeaseReturn", leaseObj)); 305 306 ILease ilease = (ILease)leaseObj; 307 308 if (ilease.InitialLeaseTime.CompareTo(TimeSpan.Zero) <= 0) 309 { 310 // No lease 311 { 312 BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, no lease because InitialLeaseTime is Zero ",obj); 313 if (ilease is System.Runtime.Remoting.Lifetime.Lease) 314 { 315 ((Lease)ilease).Remove(); 316 } 317 return nextSink; 318 } 319 } 320 321 322 Lease lease = null; 323 lock(identity) 324 { 325 if (identity.Lease != null) 326 { 327 // Lease already exists for object, object is being marsalled again 328 BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, Lease already exists for object ",obj); 329 lease = (Lease)identity.Lease; 330 lease.Renew(lease.InitialLeaseTime); // Reset initial lease time 331 } 332 else 333 { 334 // New lease 335 if (!(ilease is System.Runtime.Remoting.Lifetime.Lease)) 336 { 337 // InitializeLifetimeService created its own ILease object 338 // Need to create a System.Runtime.Remoting.Lease object 339 BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, New Lease, lease not of type Lease ",obj); 340 lease = (Lease)LifetimeServices.GetLeaseInitial(obj); 341 if (lease.CurrentState == LeaseState.Initial) 342 { 343 lease.InitialLeaseTime = ilease.InitialLeaseTime; 344 lease.RenewOnCallTime = ilease.RenewOnCallTime; 345 lease.SponsorshipTimeout = ilease.SponsorshipTimeout; 346 } 347 } 348 else 349 { 350 // An object of Type Lease was created 351 BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, New Lease, lease is type Lease ",obj); 352 lease = (Lease)ilease; 353 } 354 355 // Put lease in active state 356 // Creation phase of lease is over, properties can no longer be set on lease. 357 identity.Lease = lease; // Place lease into identity for object 358 // If the object has been marshaled activate 359 // the lease 360 if (identity.ObjectRef != null) 361 { 362 lease.ActivateLease(); 363 } 364 } 365 } 366 367 368 if (lease.RenewOnCallTime > TimeSpan.Zero) 369 { 370 // RenewOnCall create sink 371 BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, lease created ",obj); 372 return new LeaseSink(lease, nextSink); 373 } 374 else 375 { 376 // No RenewOnCall so no sink created 377 BCLDebug.Trace("REMOTE", "LeaseLifeTimeServiceProperty.GetObjectSink, No RenewOnCall so no sink created ",obj); 378 return nextSink; 379 } 380 381 } 382 383 } 384 385 } 386 387