The Labs \ Source Viewer \ SSCLI \ System.Threading \ CancellationRegion

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class:  CancellationRegion
  18. **
  19. **
  20. ** Purpose: Defines a block of code where all IO's may be
  21. ** cancelled or marked as uncancelable.  Cancellation
  22. ** regions can be nested.
  23. **
  24. **
  25. ===========================================================*/
  26. using System.Collections.Generic;
  27. using System.Security.Permissions;
  28. using System.Runtime.ConstrainedExecution;
  29. using System.Runtime.CompilerServices;
  30. namespace System.Threading
  31. {
  32.    
  33.    
  34.     public struct CancellationRegion : IDisposable
  35.     {
  36.         private CancellationSignal _signal;
  37.        
  38.         [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
  39.         private CancellationRegion(CancellationSignal signal)
  40.         {
  41.             BCLDebug.Assert(signal != null, "Must have a cancelation signal instance.");
  42.            
  43.             _signal = signal;
  44.         }
  45.        
  46.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  47.         public void Dispose()
  48.         {
  49.             if (_signal == null)
  50.                 return;
  51.            
  52.             BCLDebug.Assert(Thread.CurrentThread == _signal.Thread, "You called Dispose on the wrong thread, or reused your cancellation signal?");
  53.             List<CancellationSignal> signals = _signal.Thread.CancellationSignals;
  54.            
  55.             bool tookLock = false;
  56.             RuntimeHelpers.PrepareConstrainedRegions();
  57.             try {
  58.                 Monitor.ReliableEnter(signals, out tookLock);
  59.                 CancellationSignal s = signals[signals.Count - 1];
  60.                 signals.RemoveAt(signals.Count - 1);
  61.                 if (!Object.ReferenceEquals(s, _signal))
  62.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CancellationRegionLeak"));
  63.                 _signal.Thread = null;
  64.                 _signal = null;
  65.             }
  66.             finally {
  67.                 if (tookLock)
  68.                     Monitor.Exit(signals);
  69.                 Thread.EndThreadAffinity();
  70.             }
  71.         }
  72.        
  73.         [HostProtection(ExternalThreading = true)]
  74.         [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
  75.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  76.         public static CancellationRegion SetNonCancelable()
  77.         {
  78.             CancellationSignal signal = new CancellationSignal(false);
  79.             Thread t = Thread.CurrentThread;
  80.             signal.Thread = t;
  81.             List<CancellationSignal> signals = t.CancellationSignals;
  82.             CancellationRegion region = new CancellationRegion(signal);
  83.            
  84.             lock (signals) {
  85.                 signals.Add(signal);
  86.                 // Note that all failures due to allocations will be above
  87.                 // this point in this method. Also, note that it's fine to
  88.                 // Add first then get thread affinity later - the Cancel
  89.                 // method holds this same lock while cancelling.
  90.                 // Ensure that another fiber cannot run on this thread.
  91.                 Thread.BeginThreadAffinity();
  92.             }
  93.             return region;
  94.         }
  95.        
  96.         [HostProtection(ExternalThreading = true)]
  97.         [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
  98.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  99.         public static CancellationRegion SetCancelable(CancellationSignal signal)
  100.         {
  101.             if (signal == null)
  102.                 throw new ArgumentNullException("signal");
  103.            
  104.             Thread t = Thread.CurrentThread;
  105.             signal.Thread = t;
  106.             List<CancellationSignal> signals = t.CancellationSignals;
  107.             CancellationRegion region = new CancellationRegion(signal);
  108.            
  109.             lock (signals) {
  110.                 signals.Add(signal);
  111.                 // Note that all failures due to allocations will be above
  112.                 // this point in this method. Also, note that it's fine to
  113.                 // Add first then get thread affinity later - the Cancel
  114.                 // method holds this same lock while cancelling.
  115.                 // Ensure that another fiber cannot run on this thread.
  116.                 Thread.BeginThreadAffinity();
  117.             }
  118.             return region;
  119.         }
  120.        
  121.         // To allow CPU-intensive tasks to use our cancellation model to
  122.         // opt into cancellation via polling. We could also use this in
  123.         // select places to help avoid races inherent in the OS's
  124.         // cancellation model, such as attempting to cancel CopyFile while
  125.         // it is in the middle of some CPU-intensive calculation instead of
  126.         // blocked waiting for IO. (We could also use this in FileStream
  127.         // and other places to help support cancellation, without having to
  128.         // allocate a cancellation region).
  129.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  130.         public static void PollForCancellation()
  131.         {
  132.             Thread t = Thread.CurrentThread;
  133.             // Don't go through the property on Thread, but access the field
  134.             // directly. We don't want to create the stack if no one in the
  135.             // thread is using cancellation.
  136.             List<CancellationSignal> signals = t.m_CancellationSignals;
  137.             if (signals != null) {
  138.                 bool tookLock = false;
  139.                 RuntimeHelpers.PrepareConstrainedRegions();
  140.                 try {
  141.                     Monitor.ReliableEnter(signals, out tookLock);
  142.                     if (signals.Count > 0) {
  143.                         if (signals[signals.Count - 1].CancelRequested)
  144.                             throw new OperationCanceledException();
  145.                     }
  146.                 }
  147.                 finally {
  148.                     if (tookLock)
  149.                         Monitor.Exit(signals);
  150.                 }
  151.             }
  152.         }
  153.     }
  154. }

Developer Fusion