File: system\runtime\remoting\leasemanager.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
//+----------------------------------------------------------------------------
//
// Microsoft Windows
// File:        LeaseManager.cs
//
// Contents:    Administers the leases in an appdomain
//
// History:     1/5/00   <EMAIL>Microsoft</EMAIL>        Created
//
//+----------------------------------------------------------------------------
 
namespace System.Runtime.Remoting.Lifetime
{
    using System;
    using System.Collections;
    using System.Threading;
 
    internal class LeaseManager
    {
 
        // Lease Lists
        private Hashtable leaseToTimeTable = new Hashtable();
 
        // Async Sponsor Calls
        //private SortedList sponsorCallList = new SortedList();
        private Hashtable sponsorTable = new Hashtable();
 
 
        // LeaseTimeAnalyzer thread
        private TimeSpan pollTime;
        AutoResetEvent waitHandle;
        TimerCallback leaseTimeAnalyzerDelegate;
        private volatile Timer leaseTimer;
 
 
        internal static bool IsInitialized()
        {
            DomainSpecificRemotingData remotingData = Thread.GetDomain().RemotingData;
            LeaseManager leaseManager = remotingData.LeaseManager;
            return leaseManager != null;
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static LeaseManager GetLeaseManager(TimeSpan pollTime)
        {
            DomainSpecificRemotingData remotingData = Thread.GetDomain().RemotingData;
            LeaseManager leaseManager = remotingData.LeaseManager;
            if (leaseManager == null)
            {
                lock (remotingData)
                {
                    if (remotingData.LeaseManager == null)
                    {
                        remotingData.LeaseManager = new LeaseManager(pollTime);
                    }
                    leaseManager = remotingData.LeaseManager;
                }
            }
 
            return leaseManager;
        }
 
        internal static LeaseManager GetLeaseManager()
        {
            DomainSpecificRemotingData remotingData = Thread.GetDomain().RemotingData;
            LeaseManager leaseManager = remotingData.LeaseManager;          
            BCLDebug.Assert(leaseManager != null, "[LeaseManager.GetLeaseManager()]leaseManager !=null");
            return leaseManager;
        }
 
 
        [System.Security.SecurityCritical]  // auto-generated
        private LeaseManager(TimeSpan pollTime)
        {
            BCLDebug.Trace("REMOTE","LeaseManager Constructor");            
            this.pollTime = pollTime;
 
            leaseTimeAnalyzerDelegate = new TimerCallback(this.LeaseTimeAnalyzer);
            waitHandle = new AutoResetEvent(false);
            // We need to create a Timer with Infinite dueTime to ensure that
            // leaseTimeAnalyzerDelegate doesnt get invoked before leaseTimer is initialized
            // Once initialized we can change it to the appropriate dueTime
            leaseTimer = new Timer(leaseTimeAnalyzerDelegate, null, Timeout.Infinite, Timeout.Infinite);
            leaseTimer.Change((int)pollTime.TotalMilliseconds, Timeout.Infinite);
        }
 
 
        internal void ChangePollTime(TimeSpan pollTime)
        {
            BCLDebug.Trace("REMOTE","LeaseManager ChangePollTime ", pollTime);
            this.pollTime = pollTime;
        }
 
 
        internal void ActivateLease(Lease lease)
        {
            BCLDebug.Trace("REMOTE","LeaseManager AddLease ",lease.id," ",lease.managedObject);
            lock(leaseToTimeTable)
            {
                leaseToTimeTable[lease] = lease.leaseTime;
            }
        }       
 
        internal void DeleteLease(Lease lease)
        {
            BCLDebug.Trace("REMOTE","LeaseManager DeleteLease ",lease.id);
            lock(leaseToTimeTable)
            {
                leaseToTimeTable.Remove(lease);
            }
        }
 
        [System.Diagnostics.Conditional("_LOGGING")]
        internal void DumpLeases(Lease[] leases)
        {
            for (int i=0; i<leases.Length; i++)
            {
                BCLDebug.Trace("REMOTE","LeaseManager DumpLease ",leases[i].managedObject);                                         
            }
        }
 
 
        internal ILease GetLease(MarshalByRefObject obj)
        {
            BCLDebug.Trace("REMOTE","LeaseManager GetLease ",obj);
            bool fServer = true;
            Identity idObj = MarshalByRefObject.GetIdentity(obj, out fServer);
            if (idObj == null)
                return null;
            else
                return idObj.Lease;
        }
 
        internal void ChangedLeaseTime(Lease lease, DateTime newTime)
        {
            BCLDebug.Trace("REMOTE","LeaseManager ChangedLeaseTime ",lease.id," ",lease.managedObject," newTime ",newTime," currentTime ", DateTime.UtcNow);
            lock(leaseToTimeTable)
            {
                leaseToTimeTable[lease] = newTime;
            }
        }
 
        internal class SponsorInfo
        {
            internal Lease lease;
            internal Object sponsorId;
            internal DateTime sponsorWaitTime;
 
            internal SponsorInfo(Lease lease, Object sponsorId, DateTime sponsorWaitTime)
            {
                this.lease = lease;
                this.sponsorId = sponsorId;
                this.sponsorWaitTime = sponsorWaitTime;
            }
        }
 
        internal void RegisterSponsorCall(Lease lease, Object sponsorId, TimeSpan sponsorshipTimeOut)
        {
            BCLDebug.Trace("REMOTE","LeaseManager RegisterSponsorCall Lease ",lease," sponsorshipTimeOut ",sponsorshipTimeOut);
 
            lock(sponsorTable)
            {
                DateTime sponsorWaitTime = DateTime.UtcNow.Add(sponsorshipTimeOut);
                sponsorTable[sponsorId] = new SponsorInfo(lease, sponsorId, sponsorWaitTime);
            }
        }
 
        internal void DeleteSponsor(Object sponsorId)
        {
            lock(sponsorTable)
            {
                sponsorTable.Remove(sponsorId);
            }
        }
 
        ArrayList tempObjects = new ArrayList(10);
 
        // Thread Loop
        [System.Security.SecurityCritical]  // auto-generated
        private void LeaseTimeAnalyzer(Object state)
        {
            //BCLDebug.Trace("REMOTE","LeaseManager LeaseTimeAnalyzer Entry ",state);
 
            // Find expired leases
            DateTime now = DateTime.UtcNow;
            lock(leaseToTimeTable)
            {
                IDictionaryEnumerator e = leaseToTimeTable.GetEnumerator();
 
                while (e.MoveNext())
                {
                    DateTime time = (DateTime)e.Value;
                    Lease lease = (Lease)e.Key;
                    //BCLDebug.Trace("REMOTE","LeaseManager LeaseTimeAnalyzer lease ",lease.id, " lease time ", time, " now ", now);
                    if (time.CompareTo(now) < 0)
                    {
                        // lease expired
                        tempObjects.Add(lease);
                    }
                }
                for (int i=0; i<tempObjects.Count; i++)
                {
                    Lease lease = (Lease)tempObjects[i];
                    //BCLDebug.Trace("REMOTE","LeaseManager LeaseTimeAnalyzer lease Expired remove from leaseToTimeTable ",lease.id);
                    leaseToTimeTable.Remove(lease);
                }
 
            }
 
            // Need to run this without lock on leaseToTimeTable to avoid deadlock
            for (int i=0; i<tempObjects.Count; i++)
            {
                Lease lease = (Lease)tempObjects[i];
                //BCLDebug.Trace("REMOTE","LeaseManager LeaseTimeAnalyzer lease Expired ",lease.id);
                if (lease != null) // Lease could be deleted if there is more then one reference to the lease
                    lease.LeaseExpired(now);
            }
 
            tempObjects.Clear();                
 
            lock(sponsorTable)
            {
                IDictionaryEnumerator e = sponsorTable.GetEnumerator();
 
                while (e.MoveNext())
                {
                    // Check for SponshipTimeOuts
                    Object sponsorId = e.Key;
                    SponsorInfo sponsorInfo = (SponsorInfo)e.Value;
                    //BCLDebug.Trace("REMOTE","LeaseManager LeaseTimeAnalyzer sponsor time ", sponsorInfo.sponsorWaitTime, " now ", now);                    
                    if (sponsorInfo.sponsorWaitTime.CompareTo(now) < 0)
                    {
                        // Sponsortimeout expired expired
                        tempObjects.Add(sponsorInfo);
                    }
                }
 
                // Process the timed out sponsors
                for (int i=0; i<tempObjects.Count; i++)
                {
                    SponsorInfo sponsorInfo = (SponsorInfo)tempObjects[i];
                    //BCLDebug.Trace("REMOTE","LeaseManager LeaseTimeAnalyzer sponsor Expired remove from spansorTable", sponsorInfo.sponsorId);                    
                    sponsorTable.Remove(sponsorInfo.sponsorId);
                }
            }
 
            // Process the timed out sponsors
            // Need to run this without lock on sponsorTable to avoid deadlock
            for (int i=0; i<tempObjects.Count; i++)
            {
                SponsorInfo sponsorInfo = (SponsorInfo)tempObjects[i];
                //BCLDebug.Trace("REMOTE","LeaseManager LeaseTimeAnalyzer sponsor Expired ", sponsorInfo.sponsorId);                    
                if (sponsorInfo != null && sponsorInfo.lease != null){
                    sponsorInfo.lease.SponsorTimeout(sponsorInfo.sponsorId);
                    tempObjects[i] = null;
                }
            }
 
            tempObjects.Clear();
            leaseTimer.Change((int)pollTime.TotalMilliseconds, Timeout.Infinite);
 
            //BCLDebug.Trace("REMOTE","LeaseManager LeaseTimeAnalyzer Exit");
        }
 
    }
}