public static void Serialize(Stream stream, ManagedBitmap bitmap) { stream.Position = 0; using (BinaryWriter writer = new BinaryWriter(stream, Encoding.ASCII, true /*leaveOpen*/)) { if (bitmap is ManagedBitmap32) { writer.Write((int)32); } else if (bitmap is ManagedBitmap1) { writer.Write((int)1); } else { throw new ArgumentException(); } writer.Write((int)bitmap.Width); writer.Write((int)bitmap.Height); } int padding = (int)((PageSize - stream.Position) & (PageSize - 1)); stream.Write(new byte[padding], 0, padding); bitmap.Serialize(stream); stream.SetLength(stream.Position); }
public void StartSwapOut(ImageCache cache) { lock (this) { Debug.Assert(Program.EnableSwap); if (this.outTask != null) { return; } if (this.holders.Count != 0) { return; } Stopwatch elapsed = Stopwatch.StartNew(); #if true // TODO: remove hack EventWaitHandle swapOutDelay = new EventWaitHandle(false, EventResetMode.AutoReset); #endif Task <bool> serializationTask = null; Task <ManagedBitmap> oldBitmap = this.bitmap; // 'this' is not locked at the time 'cache' is used below in the task delegates this.outTask = new Task <bool>( delegate() { Profile profile = new Profile("SwapOut {0}", this.id); #if true // TODO: remove hack profile.Push("Hack delay for swapins"); // HACK: wait a little to allow swapins to start before swapouts EventWaitHandle localSwapOutDelay = Interlocked.Exchange(ref swapOutDelay, null); if (localSwapOutDelay != null) // race: swapin can grab and clear this before we get here { localSwapOutDelay.WaitOne(100); } profile.Pop(); // #endif profile.Push("WaitSwapOutGate"); cache.WaitSwapOutGate(); // defer to in-flight swapins profile.Pop(); lock (this) { Debug.Assert(this.swapFilePath == null); Debug.Assert(this.swapFileStream == null); this.swapFilePath = Path.GetTempFileName(); this.swapFileStream = new FileStream(this.swapFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite, 4096, FileOptions.DeleteOnClose); } profile.Push("oldBitmap.Wait()"); oldBitmap.Wait(); // wait for an old in-flight creation to complete profile.Pop(); profile.Push("Serialize"); serializationTask = new Task <bool>( delegate() { SetIOPriority(this.swapFileStream, PRIORITY_HINT.IoPriorityHintLow); ManagedBitmap.Serialize(this.swapFileStream, oldBitmap.Result); SetIOPriority(this.swapFileStream, PRIORITY_HINT.IoPriorityHintNormal); return(false); }); SerializationManager.Manager.EnqueueWriteTask(serializationTask); serializationTask.Wait(); profile.Pop(); profile.Push("Enqueue oldBitmap"); lock (this) { this.oldBitmaps.Add(oldBitmap.Result); // remove current bitmap and enqueue for destruction upon zero refs } profile.Pop(); profile.Push("Epilog"); cache.Trace("swapout", this, elapsed); cache.PurgeDisposeList(); profile.Pop(); profile.End(); //Program.Log(LogCat.Perf, profile.ToString()); return(false); }); this.bitmap = new Task <ManagedBitmap>( delegate() { Profile profile = new Profile("SwapIn {0}", this.id); profile.Push("outTask.Wait()"); #if true // TODO: remove hack // HACK: release delay immediately if swapin is requested EventWaitHandle localSwapOutDelay = Interlocked.Exchange(ref swapOutDelay, null); if (localSwapOutDelay != null) { localSwapOutDelay.Set(); } // #endif SerializationManager.Manager.Prioritize(serializationTask); Debug.Assert(this.outTask != null); this.outTask.Wait(); // ensure in-progress swapout finishes profile.Pop(); profile.Push("cache.BeginSwapIn()"); cache.BeginSwapIn(); profile.Pop(); try { Stopwatch elapsed2 = Stopwatch.StartNew(); Debug.Assert(this.swapFilePath != null); Debug.Assert(this.swapFileStream != null); profile.Push("Deserialize"); ManagedBitmap bitmap = null; Task <bool> deserializationTask = new Task <bool>( delegate() { bitmap = ManagedBitmap.Deserialize(this.swapFileStream); return(false); }); SerializationManager.Manager.EnqueueReadTask(deserializationTask); deserializationTask.Wait(); this.swapFilePath = null; Stream localSwapFileStream = this.swapFileStream; this.swapFileStream = null; localSwapFileStream.Dispose(); this.outTask = null; profile.Pop(); profile.Push("Epilog"); cache.Trace("swapin", this, elapsed2); cache.PurgeDisposeList(); StartBitmapCompleteWaiter(); return(bitmap); } finally { cache.EndSwapIn(); #if true // TODO: remove hack if (localSwapOutDelay != null) { localSwapOutDelay.Dispose(); } #endif profile.Pop(); // Epilog - here to include cache.EndSwapIn() profile.End(); //Program.Log(LogCat.Perf, profile.ToString()); } }); this.outTask.Start(); } }