Esempio n. 1
0
 public void SetLockToDispose(LockableLock newLock)
 {
     if (lockToDispose == null)
     {
         lockToDispose = newLock;
     }
     else
     {
         throw new InvalidOperationException("Lock to use has already been set for this event.");
     }
 }
Esempio n. 2
0
        //private static MUDLock CreateMUDLock(object forObject)
        //{
        //    MUDLock newLock = new MUDLock(forObject);
        //    lock (WaitUntilNoThreads)
        //    {
        //        List<MUDLock> threadLocks;
        //        if(!Locks.TryGetValue(Thread.CurrentThread, out threadLocks))
        //        {
        //            Locks[Thread.CurrentThread] = threadLocks = new List<MUDLock>();
        //        }
        //        threadLocks.Add(newLock);
        //        WaitUntilNoThreads.Set();
        //    }
        //    return newLock;
        //}
        /// <summary>
        /// Provides a unique ReaderWriterLockSlim for any object, guaranteed.
        /// </summary>
        /// <param name="forObject">object to get an associated lock object for.</param>
        /// <returns></returns>
        //private static ReaderWriterLockSlim GetRWLock(object forObject)
        //{
        //    //if (forObject == null) return null;
        //    ILockable asLockable = forObject as ILockable;
        //    ReaderWriterLockSlim rwLock;
        //    if (asLockable != null)
        //    {
        //        rwLock = asLockable.Lock;
        //        if (rwLock == null) { asLockable.Lock = rwLock = new ReaderWriterLockSlim(); }
        //        return rwLock;
        //    }
        //    //TODO: There should be a warning logged here. Ideally no object should need custom lock mutexes. Relying on this causes performance degredation.
        //    lock (CustomLocks)
        //    {
        //        if (!CustomLocks.TryGetValue(forObject, out rwLock))
        //        {
        //            rwLock = new ReaderWriterLockSlim();
        //            CustomLocks.Add(forObject, rwLock);
        //        }
        //    }
        //    return rwLock;
        //}

        //private static MUDLock GetMUDLock(object forObject, int timeout, bool ignorePause)
        //{
        //    ReaderWriterLockSlim lockObject = GetRWLock(forObject);
        //    if (ignorePause)
        //    {
        //        if (!lockObject.TryEnterWriteLock(timeout))
        //            return default(MUDLock);
        //        return CreateMUDLock(forObject);
        //    }
        //    else
        //    {
        //        DateTime start = DateTime.Now;
        //        int nextTimeout = timeout;
        //        while (true)
        //        {
        //            if (!lockObject.TryEnterWriteLock(nextTimeout))
        //                return default(MUDLock);
        //            lock (WaitUntilUnpaused)
        //            {
        //                if (MUDIsPaused) goto tryPause;
        //                return CreateMUDLock(forObject);
        //            }
        //        tryPause:
        //            //leave timeout to -1 if it was that before, or subtract the timespan used but not below 0.
        //            nextTimeout = Math.Max(Math.Min(timeout, 0), timeout - (int)TimeSpan.FromTicks(DateTime.Now.Ticks - start.Ticks).TotalMilliseconds);
        //            if (!WaitUntilUnpaused.WaitOne(nextTimeout))
        //                return default(MUDLock);
        //            nextTimeout = Math.Max(Math.Min(timeout, 0), timeout - (int)TimeSpan.FromTicks(DateTime.Now.Ticks - start.Ticks).TotalMilliseconds);
        //        }
        //    }
        //}

        /// <summary>
        /// This should be called with a using block or a similar dispose pattern.
        /// Get a lock for a specific event and resources related to that event. Returns a RoomEvent if successful, or null if
        /// it failed to get the lock.
        /// </summary>
        /// <param name="forRoom"></param>
        /// <param name="baseEvent"></param>
        /// <param name="timeout">-1 to wait forever. 0 to not wait at all. Otherwise milliseconds to wait.</param>
        /// <param name="ignorePause">Allow this to get a lock even if the MUD is paused. This probably should never be used.</param>
        /// <returns></returns>
        public static RoomEvent StartEvent(Room forRoom, RoomEvent baseEvent, int timeout = ThreadManager.DefaultTimeout, bool?ignorePause = null)
        {
            DateTime startTime = DateTime.UtcNow;

            if (baseEvent == null)
            {
                throw new ArgumentNullException("baseEvent"); //TODO: Clean this up.
            }
            //baseEvent = new SimpleRoomEvent();

            //Skip MUDIsPaused check if this thread is already modifying MUD state.
            bool         skipThisPause = (ignorePause == null ? LockableLockGroup.HasALock() : ignorePause.Value);
            IDisposable  MUDLock       = null;
            LockableLock foundLock     = null;

            try
            {
                MUDLock = skipThisPause ? GetMUDLockIgnorePause() : GetMUDLock(startTime.RemainingTimeout(timeout));
                if (MUDLock != null)
                {
                    foundLock = forRoom.EnterLock(baseEvent, startTime.RemainingTimeout(timeout));
                    if (foundLock == null) //Failed to get a lock.
                    {
                        return(null);
                    }
                    baseEvent.SetLockToDispose(foundLock);
                    foundLock = null;
                    //Important weird thing: This is basically 'passing off' the lock from this function to baseEvent.
                    //Setting MUDLock to null prevents it being disposed of right now, and when baseEvent is disposed
                    //of later it will do the same cleanup MUDLock would have done.
                    MUDLock = null;
                    return(baseEvent);
                }
            }
            finally
            {
                if (MUDLock != null)
                {
                    MUDLock.Dispose();
                }
                if (foundLock != null)
                {
                    foundLock.Dispose();
                }
            }
            return(null);
        }