//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: XRef.cs // // Note: File is part of Sing# runtime files and copied into Singularity tree // whenever a new version of Sing# is dropped. // using System; using Microsoft.SingSharp; using Microsoft.Singularity.Memory; namespace Microsoft.Singularity.Channels { using System.Threading; using Allocation = Microsoft.Singularity.Memory.SharedHeap.Allocation; public sealed class ExRef where T : unmanaged struct, ITracked { unsafe T* opt(ExHeap) obj; Mutex mutex; public ExRef([Claims] T* opt(ExHeap)! i_obj, bool synchronized) { if (i_obj == null) { throw new ArgumentNullException("ExRef must be initialized with a non-null value!"); } i_obj->Release(); obj = i_obj; if (synchronized) { this.mutex = new Mutex(); } } // invariant: // If mutex is held, thread holding mutex is // responsible for calling Release during that time, // the obj slot is empty and if the thread tries to // acquire it again, an exception is thrown. /// /// Will block until the ExRef is free. /// /// Acquired tracked type protected by ExRef public T* opt(ExHeap)! Acquire() { if (this.mutex != null) { this.mutex.WaitOne(); } T* opt(ExHeap) elem = this.obj; if (elem == null) { throw new ApplicationException("thread already holds ExRef!"); } elem->Acquire(); this.obj = null; return elem; } /// /// Releases tracked data into the ExRef so other /// threads can access it. /// /// tracked data to be released public void Release([Claims] T* opt(ExHeap)! newObj) { if (newObj == null) { throw new ArgumentNullException("ExRef must be released with a non-null value!"); } T* opt(ExHeap) elem = this.obj; if (elem != null) { throw new ApplicationException("Releasing into occupied slot!"); } newObj->Release(); obj = newObj; if (this.mutex != null) { this.mutex.ReleaseMutex(); } } /// /// Finalizer to dispose of any left over contents /// ~ExRef() { T* opt(ExHeap) toDelete = this.obj; if (toDelete != null) { this.obj = null; unsafe { toDelete->Dispose(); // Explicit call needed due to generics } delete toDelete; } } } }