/* Copyright (c) Cloud Software Group, Inc. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System.Collections.Generic; using System.Threading; // Copied from http://www.boyet.com/Articles/LockfreeQueue.html // Contacted author for licences conditions 10/03/08, none // state on blog // IEnumerable added by Tom Wilkie (Citrix) namespace XenCenterLib { internal class SingleLinkNode { // Note; the Next member cannot be a property since it participates in // many CAS operations public SingleLinkNode Next; public T Item; } public class LockFreeQueue : IEnumerable { SingleLinkNode head; SingleLinkNode tail; public LockFreeQueue() { head = new SingleLinkNode(); tail = head; } private static bool CAS(ref S location, S comparand, S newValue) where S : class { return (object)comparand == (object)Interlocked.CompareExchange(ref location, newValue, comparand); } public void Enqueue(T item) { SingleLinkNode oldTail = null; SingleLinkNode oldTailNext; SingleLinkNode newNode = new SingleLinkNode(); newNode.Item = item; bool newNodeWasAdded = false; while (!newNodeWasAdded) { oldTail = tail; oldTailNext = oldTail.Next; if (tail == oldTail) { if (oldTailNext == null) newNodeWasAdded = CAS>(ref tail.Next, null, newNode); else CAS>(ref tail, oldTail, oldTailNext); } } CAS>(ref tail, oldTail, newNode); } public bool Dequeue(out T item) { item = default(T); SingleLinkNode oldHead = null; bool haveAdvancedHead = false; while (!haveAdvancedHead) { oldHead = head; SingleLinkNode oldTail = tail; SingleLinkNode oldHeadNext = oldHead.Next; if (oldHead == head) { if (oldHead == oldTail) { if (oldHeadNext == null) { return false; } CAS>(ref tail, oldTail, oldHeadNext); } else { item = oldHeadNext.Item; haveAdvancedHead = CAS>(ref head, oldHead, oldHeadNext); } } } return true; } public T Dequeue() { T result; Dequeue(out result); return result; } public bool NotEmpty { get { return head.Next != null; } } #region IEnumerable Members private class LockFreeQueueEnumerator : IEnumerator { private readonly LockFreeQueue queue; private SingleLinkNode current; public LockFreeQueueEnumerator(LockFreeQueue queue) { this.queue = queue; this.current = queue.head; } #region IEnumerator Members public U Current { get { return current.Item; } } #endregion #region IDisposable Members public void Dispose() { } #endregion #region IEnumerator Members object System.Collections.IEnumerator.Current { get { return Current; } } public bool MoveNext() { if (current.Next == null) return false; current = current.Next; return true; } public void Reset() { current = queue.head; } #endregion } /// /// This function is not lock-free, and must only be used if no-one if reading from the list. /// This is fine for our use, as we only need to enumerate a queue when we first populate the cache. /// /// public IEnumerator GetEnumerator() { return new LockFreeQueueEnumerator(this); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion } }