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

  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: ThreadPool
  18. **
  19. **
  20. ** Purpose: Class for creating and managing a threadpool
  21. **
  22. **
  23. =============================================================================*/
  24. /*
  25. * Below you'll notice two sets of APIs that are separated by the
  26. * use of 'Unsafe' in their names.  The unsafe versions are called
  27. * that because they do not propagate the calling stack onto the
  28. * worker thread.  This allows code to lose the calling stack and
  29. * thereby elevate its security privileges.  Note that this operation
  30. * is much akin to the combined ability to control security policy
  31. * and control security evidence.  With these privileges, a person
  32. * can gain the right to load assemblies that are fully trusted which
  33. * then assert full trust and can call any code they want regardless
  34. * of the previous stack information.
  35. */
  36. namespace System.Threading
  37. {
  38.     using System.Security;
  39.     using System.Threading;
  40.     using System.Runtime.Remoting;
  41.     using System.Security.Permissions;
  42.     using System;
  43.     using Microsoft.Win32;
  44.     using System.Runtime.CompilerServices;
  45.     using System.Runtime.ConstrainedExecution;
  46.     using System.Runtime.InteropServices;
  47.    
  48.     internal sealed class RegisteredWaitHandleSafe : CriticalFinalizerObject
  49.     {
  50.         private static readonly IntPtr InvalidHandle = Win32Native.INVALID_HANDLE_VALUE;
  51.         private IntPtr registeredWaitHandle;
  52.         private WaitHandle m_internalWaitObject;
  53.         private bool bReleaseNeeded = false;
  54.         private int m_lock = 0;
  55.        
  56.         internal RegisteredWaitHandleSafe()
  57.         {
  58.             registeredWaitHandle = InvalidHandle;
  59.         }
  60.        
  61.         internal IntPtr GetHandle()
  62.         {
  63.             return registeredWaitHandle;
  64.         }
  65.        
  66.         internal void SetHandle(IntPtr handle)
  67.         {
  68.             registeredWaitHandle = handle;
  69.         }
  70.        
  71.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  72.         internal void SetWaitObject(WaitHandle waitObject)
  73.         {
  74.             // needed for DangerousAddRef
  75.             RuntimeHelpers.PrepareConstrainedRegions();
  76.             try {
  77.             }
  78.             finally {
  79.                 m_internalWaitObject = waitObject;
  80.                 if (waitObject != null) {
  81.                     m_internalWaitObject.SafeWaitHandle.DangerousAddRef(ref bReleaseNeeded);
  82.                 }
  83.             }
  84.         }
  85.        
  86.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  87.         // object to be notified when all callbacks to delegates have completed
  88.         internal bool Unregister(WaitHandle waitObject)
  89.         {
  90.             bool result = false;
  91.             // needed for DangerousRelease
  92.             RuntimeHelpers.PrepareConstrainedRegions();
  93.             try {
  94.             }
  95.             finally {
  96.                 // lock(this) cannot be used reliably in Cer since thin lock could be
  97.                 // promoted to syncblock and that is not a guaranteed operation
  98.                 bool bLockTaken = false;
  99.                 do {
  100.                     if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0) {
  101.                         bLockTaken = true;
  102.                         try {
  103.                             if (ValidHandle()) {
  104.                                 result = UnregisterWaitNative(GetHandle(), waitObject == null ? null : waitObject.SafeWaitHandle);
  105.                                 if (result == true) {
  106.                                     if (bReleaseNeeded) {
  107.                                         m_internalWaitObject.SafeWaitHandle.DangerousRelease();
  108.                                         bReleaseNeeded = false;
  109.                                     }
  110.                                     // if result not true don't release/suppress here so finalizer can make another attempt
  111.                                     SetHandle(InvalidHandle);
  112.                                     m_internalWaitObject = null;
  113.                                     GC.SuppressFinalize(this);
  114.                                 }
  115.                             }
  116.                         }
  117.                         finally {
  118.                             m_lock = 0;
  119.                         }
  120.                     }
  121.                     Thread.SpinWait(1);
  122.                     // yield to processor
  123.                 }
  124.                 while (!bLockTaken);
  125.             }
  126.             return result;
  127.         }
  128.        
  129.         private bool ValidHandle()
  130.         {
  131.             return (registeredWaitHandle != InvalidHandle && registeredWaitHandle != IntPtr.Zero);
  132.         }
  133.        
  134.         ~RegisteredWaitHandleSafe()
  135.         {
  136.             // if the app has already unregistered the wait, there is nothing to cleanup
  137.             // we can detect this by checking the handle. Normally, there is no race here
  138.             // so no need to protect reading of handle. However, if this object gets
  139.             // resurrected and then someone does an unregister, it would introduce a race
  140.            
  141.             // PrepareConstrainedRegions call not needed since finalizer already in Cer
  142.            
  143.             // lock(this) cannot be used reliably even in Cer since thin lock could be
  144.             // promoted to syncblock and that is not a guaranteed operation
  145.            
  146.             bool bLockTaken = false;
  147.             do {
  148.                 if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0) {
  149.                     bLockTaken = true;
  150.                     try {
  151.                         if (ValidHandle()) {
  152.                             WaitHandleCleanupNative(registeredWaitHandle);
  153.                             if (bReleaseNeeded) {
  154.                                 m_internalWaitObject.SafeWaitHandle.DangerousRelease();
  155.                                 bReleaseNeeded = false;
  156.                             }
  157.                             SetHandle(InvalidHandle);
  158.                             m_internalWaitObject = null;
  159.                         }
  160.                     }
  161.                     finally {
  162.                         m_lock = 0;
  163.                     }
  164.                 }
  165.                 Thread.SpinWait(1);
  166.                 // yield to processor
  167.             }
  168.             while (!bLockTaken);
  169.         }
  170.        
  171.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  172.         private static extern void WaitHandleCleanupNative(IntPtr handle);
  173.        
  174.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  175.         private static extern bool UnregisterWaitNative(IntPtr handle, SafeHandle waitObject);
  176.     }
  177.    
  178.     [System.Runtime.InteropServices.ComVisible(true)]
  179.     public sealed class RegisteredWaitHandle : MarshalByRefObject
  180.     {
  181.         private RegisteredWaitHandleSafe internalRegisteredWait;
  182.        
  183.         internal RegisteredWaitHandle()
  184.         {
  185.             internalRegisteredWait = new RegisteredWaitHandleSafe();
  186.         }
  187.        
  188.         internal void SetHandle(IntPtr handle)
  189.         {
  190.             internalRegisteredWait.SetHandle(handle);
  191.         }
  192.        
  193.         internal void SetWaitObject(WaitHandle waitObject)
  194.         {
  195.             internalRegisteredWait.SetWaitObject(waitObject);
  196.         }
  197.        
  198.        
  199.         [System.Runtime.InteropServices.ComVisible(true)]
  200.         // This is the only public method on this class
  201.         // object to be notified when all callbacks to delegates have completed
  202.         public bool Unregister(WaitHandle waitObject)
  203.         {
  204.             return internalRegisteredWait.Unregister(waitObject);
  205.         }
  206.     }
  207.    
  208.     [System.Runtime.InteropServices.ComVisible(true)]
  209.     public delegate void WaitCallback(object state);
  210.    
  211.     [System.Runtime.InteropServices.ComVisible(true)]
  212.     public delegate void WaitOrTimerCallback(object state, bool timedOut);
  213.     // signalled or timed out
  214.     internal class _ThreadPoolWaitCallback
  215.     {
  216.         WaitCallback _waitCallback;
  217.         ExecutionContext _executionContext;
  218.         object _state;
  219.        
  220.         static internal ContextCallback _ccb = new ContextCallback(WaitCallback_Context);
  221.         static internal void WaitCallback_Context(object state)
  222.         {
  223.             _ThreadPoolWaitCallback obj = (_ThreadPoolWaitCallback)state;
  224.             obj._waitCallback(obj._state);
  225.         }
  226.        
  227.        
  228.         internal _ThreadPoolWaitCallback(WaitCallback waitCallback, object state, bool compressStack, ref StackCrawlMark stackMark)
  229.         {
  230.             _waitCallback = waitCallback;
  231.             _state = state;
  232.             if (compressStack && !ExecutionContext.IsFlowSuppressed()) {
  233.                 // clone the exection context
  234.                 _executionContext = ExecutionContext.Capture(ref stackMark);
  235.                 ExecutionContext.ClearSyncContext(_executionContext);
  236.             }
  237.         }
  238.        
  239.         // call back helper
  240.         static internal void PerformWaitCallback(object state)
  241.         {
  242.             _ThreadPoolWaitCallback helper = (_ThreadPoolWaitCallback)state;
  243.            
  244.             BCLDebug.Assert(helper != null, "Null state passed to PerformWaitCallback!");
  245.             // call directly if it is an unsafe call OR EC flow is suppressed
  246.             if (helper._executionContext == null) {
  247.                 WaitCallback callback = helper._waitCallback;
  248.                 callback(helper._state);
  249.             }
  250.             else {
  251.                 ExecutionContext.Run(helper._executionContext, _ccb, helper);
  252.             }
  253.         }
  254.     }
  255.    
  256.     internal class _ThreadPoolWaitOrTimerCallback
  257.     {
  258.         WaitOrTimerCallback _waitOrTimerCallback;
  259.         ExecutionContext _executionContext;
  260.         object _state;
  261.         private static ContextCallback _ccbt = new ContextCallback(WaitOrTimerCallback_Context_t);
  262.         private static ContextCallback _ccbf = new ContextCallback(WaitOrTimerCallback_Context_f);
  263.        
  264.         internal _ThreadPoolWaitOrTimerCallback(WaitOrTimerCallback waitOrTimerCallback, object state, bool compressStack, ref StackCrawlMark stackMark)
  265.         {
  266.             _waitOrTimerCallback = waitOrTimerCallback;
  267.             _state = state;
  268.             if (compressStack && !ExecutionContext.IsFlowSuppressed()) {
  269.                 // capture the exection context
  270.                 _executionContext = ExecutionContext.Capture(ref stackMark);
  271.                 ExecutionContext.ClearSyncContext(_executionContext);
  272.             }
  273.         }
  274.         private static void WaitOrTimerCallback_Context_t(object state)
  275.         {
  276.             WaitOrTimerCallback_Context(state, true);
  277.         }
  278.         private static void WaitOrTimerCallback_Context_f(object state)
  279.         {
  280.             WaitOrTimerCallback_Context(state, false);
  281.         }
  282.        
  283.         private static void WaitOrTimerCallback_Context(object state, bool timedOut)
  284.         {
  285.             _ThreadPoolWaitOrTimerCallback helper = (_ThreadPoolWaitOrTimerCallback)state;
  286.             helper._waitOrTimerCallback(helper._state, timedOut);
  287.         }
  288.        
  289.        
  290.         // call back helper
  291.         static internal void PerformWaitOrTimerCallback(object state, bool timedOut)
  292.         {
  293.             _ThreadPoolWaitOrTimerCallback helper = (_ThreadPoolWaitOrTimerCallback)state;
  294.             BCLDebug.Assert(helper != null, "Null state passed to PerformWaitOrTimerCallback!");
  295.             // call directly if it is an unsafe call OR EC flow is suppressed
  296.             if (helper._executionContext == null) {
  297.                 WaitOrTimerCallback callback = helper._waitOrTimerCallback;
  298.                 callback(helper._state, timedOut);
  299.             }
  300.             else {
  301.                 if (timedOut)
  302.                     ExecutionContext.Run(helper._executionContext.CreateCopy(), _ccbt, helper);
  303.                 else
  304.                     ExecutionContext.Run(helper._executionContext.CreateCopy(), _ccbf, helper);
  305.             }
  306.         }
  307.     }
  308.    
  309.     [CLSCompliant(false)]
  310.     [System.Runtime.InteropServices.ComVisible(true)]
  311.         // Error code
  312.         // No. of bytes transferred
  313.         // ptr to OVERLAP structure
  314.     unsafe public delegate void IOCompletionCallback(uint errorCode, uint numBytes, NativeOverlapped* pOVERLAP);
  315.    
  316.     [HostProtection(Synchronization = true, ExternalThreading = true)]
  317.     public static class ThreadPool
  318.     {
  319.        
  320.         [SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
  321.         public static bool SetMaxThreads(int workerThreads, int completionPortThreads)
  322.         {
  323.             return SetMaxThreadsNative(workerThreads, completionPortThreads);
  324.         }
  325.        
  326.         public static void GetMaxThreads(out int workerThreads, out int completionPortThreads)
  327.         {
  328.             GetMaxThreadsNative(out workerThreads, out completionPortThreads);
  329.         }
  330.        
  331.         [SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
  332.         public static bool SetMinThreads(int workerThreads, int completionPortThreads)
  333.         {
  334.             return SetMinThreadsNative(workerThreads, completionPortThreads);
  335.         }
  336.        
  337.         public static void GetMinThreads(out int workerThreads, out int completionPortThreads)
  338.         {
  339.             GetMinThreadsNative(out workerThreads, out completionPortThreads);
  340.         }
  341.        
  342.         public static void GetAvailableThreads(out int workerThreads, out int completionPortThreads)
  343.         {
  344.             GetAvailableThreadsNative(out workerThreads, out completionPortThreads);
  345.         }
  346.        
  347.         [CLSCompliant(false)]
  348.             // throws RegisterWaitException
  349.         // NOTE: we do not allow other options that allow the callback to be queued as an APC
  350.         public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, uint millisecondsTimeOutInterval, bool executeOnlyOnce)
  351.         {
  352.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  353.             return RegisterWaitForSingleObject(waitObject, callBack, state, millisecondsTimeOutInterval, executeOnlyOnce, ref stackMark, true);
  354.         }
  355.        
  356.         [CLSCompliant(false), SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.ControlEvidence | SecurityPermissionFlag.ControlPolicy)]
  357.             // throws RegisterWaitException
  358.         // NOTE: we do not allow other options that allow the callback to be queued as an APC
  359.         public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, uint millisecondsTimeOutInterval, bool executeOnlyOnce)
  360.         {
  361.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  362.             return RegisterWaitForSingleObject(waitObject, callBack, state, millisecondsTimeOutInterval, executeOnlyOnce, ref stackMark, false);
  363.         }
  364.        
  365.        
  366.             // throws RegisterWaitException
  367.             // NOTE: we do not allow other options that allow the callback to be queued as an APC
  368.         private static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, uint millisecondsTimeOutInterval, bool executeOnlyOnce, ref StackCrawlMark stackMark, bool compressStack)
  369.         {
  370.             if (RemotingServices.IsTransparentProxy(waitObject))
  371.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_WaitOnTransparentProxy"));
  372.             RegisteredWaitHandle registeredWaitHandle = new RegisteredWaitHandle();
  373.            
  374.             if (callBack != null) {
  375.                 _ThreadPoolWaitOrTimerCallback callBackHelper = new _ThreadPoolWaitOrTimerCallback(callBack, state, compressStack, ref stackMark);
  376.                 state = (object)callBackHelper;
  377.                 // call SetWaitObject before native call so that waitObject won't be closed before threadpoolmgr registration
  378.                 // this could occur if callback were to fire before SetWaitObject does its addref
  379.                 registeredWaitHandle.SetWaitObject(waitObject);
  380.                 IntPtr nativeRegisteredWaitHandle = RegisterWaitForSingleObjectNative(waitObject, state, millisecondsTimeOutInterval, executeOnlyOnce, registeredWaitHandle, ref stackMark, compressStack);
  381.                 registeredWaitHandle.SetHandle(nativeRegisteredWaitHandle);
  382.             }
  383.             else {
  384.                 throw new ArgumentNullException("WaitOrTimerCallback");
  385.             }
  386.             return registeredWaitHandle;
  387.         }
  388.        
  389.        
  390.        
  391.             // throws RegisterWaitException
  392.         // NOTE: we do not allow other options that allow the callback to be queued as an APC
  393.         public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, int millisecondsTimeOutInterval, bool executeOnlyOnce)
  394.         {
  395.             if (millisecondsTimeOutInterval < -1)
  396.                 throw new ArgumentOutOfRangeException("millisecondsTimeOutInterval", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
  397.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  398.             return RegisterWaitForSingleObject(waitObject, callBack, state, (UInt32)millisecondsTimeOutInterval, executeOnlyOnce, ref stackMark, true);
  399.         }
  400.        
  401.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.ControlEvidence | SecurityPermissionFlag.ControlPolicy)]
  402.             // throws RegisterWaitException
  403.         // NOTE: we do not allow other options that allow the callback to be queued as an APC
  404.         public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, int millisecondsTimeOutInterval, bool executeOnlyOnce)
  405.         {
  406.             if (millisecondsTimeOutInterval < -1)
  407.                 throw new ArgumentOutOfRangeException("millisecondsTimeOutInterval", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
  408.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  409.             return RegisterWaitForSingleObject(waitObject, callBack, state, (UInt32)millisecondsTimeOutInterval, executeOnlyOnce, ref stackMark, false);
  410.         }
  411.        
  412.             // throws RegisterWaitException
  413.         // NOTE: we do not allow other options that allow the callback to be queued as an APC
  414.         public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, long millisecondsTimeOutInterval, bool executeOnlyOnce)
  415.         {
  416.             if (millisecondsTimeOutInterval < -1)
  417.                 throw new ArgumentOutOfRangeException("millisecondsTimeOutInterval", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
  418.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  419.             return RegisterWaitForSingleObject(waitObject, callBack, state, (UInt32)millisecondsTimeOutInterval, executeOnlyOnce, ref stackMark, true);
  420.         }
  421.        
  422.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.ControlEvidence | SecurityPermissionFlag.ControlPolicy)]
  423.             // throws RegisterWaitException
  424.         // NOTE: we do not allow other options that allow the callback to be queued as an APC
  425.         public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, long millisecondsTimeOutInterval, bool executeOnlyOnce)
  426.         {
  427.             if (millisecondsTimeOutInterval < -1)
  428.                 throw new ArgumentOutOfRangeException("millisecondsTimeOutInterval", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
  429.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  430.             return RegisterWaitForSingleObject(waitObject, callBack, state, (UInt32)millisecondsTimeOutInterval, executeOnlyOnce, ref stackMark, false);
  431.         }
  432.        
  433.        
  434.         public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, TimeSpan timeout, bool executeOnlyOnce)
  435.         {
  436.             long tm = (long)timeout.TotalMilliseconds;
  437.             if (tm < -1)
  438.                 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
  439.             if (tm > (long)Int32.MaxValue)
  440.                 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_LessEqualToIntegerMaxVal"));
  441.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  442.             return RegisterWaitForSingleObject(waitObject, callBack, state, (UInt32)tm, executeOnlyOnce, ref stackMark, true);
  443.         }
  444.        
  445.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.ControlEvidence | SecurityPermissionFlag.ControlPolicy)]
  446.         public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, TimeSpan timeout, bool executeOnlyOnce)
  447.         {
  448.             long tm = (long)timeout.TotalMilliseconds;
  449.             if (tm < -1)
  450.                 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
  451.             if (tm > (long)Int32.MaxValue)
  452.                 throw new ArgumentOutOfRangeException("timeout", Environment.GetResourceString("ArgumentOutOfRange_LessEqualToIntegerMaxVal"));
  453.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  454.             return RegisterWaitForSingleObject(waitObject, callBack, state, (UInt32)tm, executeOnlyOnce, ref stackMark, false);
  455.         }
  456.        
  457.             // NOTE: we do not expose options that allow the callback to be queued as an APC
  458.         public static bool QueueUserWorkItem(WaitCallback callBack, object state)
  459.         {
  460.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  461.             return QueueUserWorkItemHelper(callBack, state, ref stackMark, true);
  462.         }
  463.        
  464.         // NOTE: we do not expose options that allow the callback to be queued as an APC
  465.         public static bool QueueUserWorkItem(WaitCallback callBack)
  466.         {
  467.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  468.             return QueueUserWorkItemHelper(callBack, null, ref stackMark, true);
  469.         }
  470.        
  471.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.ControlEvidence | SecurityPermissionFlag.ControlPolicy)]
  472.             // NOTE: we do not expose options that allow the callback to be queued as an APC
  473.         public static bool UnsafeQueueUserWorkItem(WaitCallback callBack, object state)
  474.         {
  475.             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  476.             return QueueUserWorkItemHelper(callBack, state, ref stackMark, false);
  477.         }
  478.        
  479.         private static bool QueueUserWorkItemHelper(WaitCallback callBack, object state, ref StackCrawlMark stackMark, bool compressStack)
  480.         {
  481.             if (callBack != null) {
  482.                 _ThreadPoolWaitCallback callBackHelper = new _ThreadPoolWaitCallback(callBack, state, compressStack, ref stackMark);
  483.                 state = (object)callBackHelper;
  484.                 return QueueUserWorkItem(state, ref stackMark, compressStack);
  485.             }
  486.             else {
  487.                 throw new ArgumentNullException("WaitCallback");
  488.             }
  489.            
  490.         }
  491.        
  492.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  493.         private static extern bool QueueUserWorkItem(object state, ref StackCrawlMark stackMark, bool compressStack);
  494.        
  495.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  496.         unsafe private static extern bool PostQueuedCompletionStatus(NativeOverlapped* overlapped);
  497.        
  498.         [CLSCompliant(false)]
  499.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.ControlEvidence | SecurityPermissionFlag.ControlPolicy)]
  500.         unsafe public static bool UnsafeQueueNativeOverlapped(NativeOverlapped* overlapped)
  501.         {
  502.             return PostQueuedCompletionStatus(overlapped);
  503.         }
  504.        
  505.         // Native methods:
  506.        
  507.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  508.         private static extern bool SetMinThreadsNative(int workerThreads, int completionPortThreads);
  509.        
  510.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  511.         private static extern bool SetMaxThreadsNative(int workerThreads, int completionPortThreads);
  512.        
  513.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  514.         private static extern void GetMinThreadsNative(out int workerThreads, out int completionPortThreads);
  515.        
  516.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  517.         private static extern void GetMaxThreadsNative(out int workerThreads, out int completionPortThreads);
  518.        
  519.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  520.         private static extern void GetAvailableThreadsNative(out int workerThreads, out int completionPortThreads);
  521.        
  522.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  523.         private static extern IntPtr RegisterWaitForSingleObjectNative(WaitHandle waitHandle, object state, uint timeOutInterval, bool executeOnlyOnce, RegisteredWaitHandle registeredWaitHandle, ref StackCrawlMark stackMark, bool compressStack);
  524.        
  525.         [Obsolete("ThreadPool.BindHandle(IntPtr) has been deprecated. Please use ThreadPool.BindHandle(SafeHandle) instead.", false)]
  526.         [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  527.         public static bool BindHandle(IntPtr osHandle)
  528.         {
  529.             return BindIOCompletionCallbackNative(osHandle);
  530.         }
  531.        
  532.         [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  533.         public static bool BindHandle(SafeHandle osHandle)
  534.         {
  535.             if (osHandle == null)
  536.                 throw new ArgumentNullException("osHandle");
  537.            
  538.             bool ret = false;
  539.             bool mustReleaseSafeHandle = false;
  540.             RuntimeHelpers.PrepareConstrainedRegions();
  541.             try {
  542.                 osHandle.DangerousAddRef(ref mustReleaseSafeHandle);
  543.                 ret = BindIOCompletionCallbackNative(osHandle.DangerousGetHandle());
  544.             }
  545.             finally {
  546.                 if (mustReleaseSafeHandle)
  547.                     osHandle.DangerousRelease();
  548.             }
  549.             return ret;
  550.         }
  551.        
  552.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  553.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  554.         private static extern bool BindIOCompletionCallbackNative(IntPtr fileHandle);
  555.     }
  556. }

Developer Fusion