Example #1
0
        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();
            }
        }