Example #1
0
        // This is the worker delegate that is called on the Threadpool thread to fire the actual events. It sets the DelegateStarted flag so
        // the thread that queued the work to the threadpool knows it has started (since it does not want to block indefinitely on the task
        // to start).
        private static void ControlCDelegate(object data)
        {
            ControlCDelegateData controlCData = (ControlCDelegateData)data;

            controlCData.DelegateStarted = true;
            ConsoleCancelEventArgs args = new ConsoleCancelEventArgs(controlCData.ControlKey);

            controlCData.CancelCallbacks(null, args);
            controlCData.Cancel = args.Cancel;
        }
        // Returns true if we've "handled" the break request, false if
        // we want to terminate the process (or at least let the next
        // control handler function have a chance).
        private static bool BreakEvent(int controlType)
        {
            // The thread that this gets called back on has a very small stack on 64 bit systems. There is
            // not enough space to handle a managed exception being caught and thrown. So, queue up a work
            // item on another thread for the actual event callback.

            if (controlType == Win32Native.CTRL_C_EVENT ||
                controlType == Win32Native.CTRL_BREAK_EVENT)
            {
                // To avoid race between remove handler and raising the event
                ConsoleCancelEventHandler cancelCallbacks = Console._cancelCallbacks;
                if (cancelCallbacks == null)
                {
                    return(false);
                }

                // Create the delegate
                ConsoleSpecialKey    controlKey       = (controlType == 0) ? ConsoleSpecialKey.ControlC : ConsoleSpecialKey.ControlBreak;
                ControlCDelegateData delegateData     = new ControlCDelegateData(controlKey, cancelCallbacks);
                WaitCallback         controlCCallback = new WaitCallback(ControlCDelegate);

                // Queue the delegate
                if (!ThreadPool.QueueUserWorkItem(controlCCallback, delegateData))
                {
                    BCLDebug.Assert(false, "ThreadPool.QueueUserWorkItem returned false without throwing. Unable to execute ControlC handler");
                    return(false);
                }
                // Block until the delegate is done. We need to be robust in the face of the work item not executing
                // but we also want to get control back immediately after it is done and we don't want to give the
                // handler a fixed time limit in case it needs to display UI. Wait on the event twice, once with a
                // timout and a second time without if we are sure that the handler actually started.
                TimeSpan controlCWaitTime = new TimeSpan(0, 0, 30); // 30 seconds
                delegateData.CompletionEvent.WaitOne(controlCWaitTime, false);
                if (!delegateData.DelegateStarted)
                {
                    BCLDebug.Assert(false, "ThreadPool.QueueUserWorkItem did not execute the handler within 30 seconds.");
                    return(false);
                }
                delegateData.CompletionEvent.WaitOne();
                delegateData.CompletionEvent.Close();
                return(delegateData.Cancel);
            }
            return(false);
        }
Example #3
0
        internal static bool HandleBreakEvent(ConsoleSpecialKey controlKey)
        {
            // The thread that this gets called back on has a very small stack on some systems. There is
            // not enough space to handle a managed exception being caught and thrown. So, run a task
            // on the threadpool for the actual event callback.

            // To avoid the race condition between remove handler and raising the event
            ConsoleCancelEventHandler cancelCallbacks = Console._cancelCallbacks;

            if (cancelCallbacks == null)
            {
                return(false);
            }

            var  delegateData = new ControlCDelegateData(controlKey, cancelCallbacks);
            Task callBackTask = Task.Factory.StartNew(
                d => ((ControlCDelegateData)d).HandleBreakEvent(),
                delegateData,
                CancellationToken.None,
                TaskCreationOptions.DenyChildAttach,
                TaskScheduler.Default);

            // Block until the delegate is done. We need to be robust in the face of the task not executing
            // but we also want to get control back immediately after it is done and we don't want to give the
            // handler a fixed time limit in case it needs to display UI. Wait on the task twice, once with a
            // timeout and a second time without if we are sure that the handler actually started.
            TimeSpan controlCWaitTime = new TimeSpan(0, 0, 30); // 30 seconds

            callBackTask.Wait(controlCWaitTime);

            if (!delegateData.DelegateStarted)
            {
                Debug.Assert(false, "The task to execute the handler did not start within 30 seconds.");
                return(false);
            }

            callBackTask.Wait();
            return(delegateData.Cancel);
        }
Example #4
0
        // Returns true if we've "handled" the break request, false if
        // we want to terminate the process (or at least let the next 
        // control handler function have a chance). 
        private static bool BreakEvent(int controlType) {
 
            // The thread that this gets called back on has a very small stack on 64 bit systems. There is
            // not enough space to handle a managed exception being caught and thrown. So, queue up a work
            // item on another thread for the actual event callback.
 
            if (controlType == Win32Native.CTRL_C_EVENT ||
                controlType == Win32Native.CTRL_BREAK_EVENT) { 
 
                // To avoid ---- between remove handler and raising the event
                ConsoleCancelEventHandler cancelCallbacks = Console._cancelCallbacks; 
                if (cancelCallbacks == null) {
                    return false;
                }
 
                // Create the delegate
                ConsoleSpecialKey controlKey = (controlType == 0) ? ConsoleSpecialKey.ControlC : ConsoleSpecialKey.ControlBreak; 
                ControlCDelegateData delegateData = new ControlCDelegateData(controlKey, cancelCallbacks); 
                WaitCallback controlCCallback = new WaitCallback(ControlCDelegate);
 
                // Queue the delegate
                if (!ThreadPool.QueueUserWorkItem(controlCCallback, delegateData)) {
                    Contract.Assert(false, "ThreadPool.QueueUserWorkItem returned false without throwing. Unable to execute ControlC handler");
                    return false; 
                }
                // Block until the delegate is done. We need to be robust in the face of the work item not executing 
                // but we also want to get control back immediately after it is done and we don't want to give the 
                // handler a fixed time limit in case it needs to display UI. Wait on the event twice, once with a
                // timout and a second time without if we are sure that the handler actually started. 
                TimeSpan controlCWaitTime = new TimeSpan(0, 0, 30); // 30 seconds
                delegateData.CompletionEvent.WaitOne(controlCWaitTime, false);
                if (!delegateData.DelegateStarted) {
                    Contract.Assert(false, "ThreadPool.QueueUserWorkItem did not execute the handler within 30 seconds."); 
                    return false;
                } 
                delegateData.CompletionEvent.WaitOne(); 
                delegateData.CompletionEvent.Close();
                return delegateData.Cancel; 

            }
            return false;
        } 
 private static bool BreakEvent(int controlType)
 {
     if ((controlType != 0) && (controlType != 1))
     {
         return false;
     }
     ConsoleCancelEventHandler cancelCallbacks = _cancelCallbacks;
     if (cancelCallbacks == null)
     {
         return false;
     }
     ConsoleSpecialKey controlKey = (controlType == 0) ? ConsoleSpecialKey.ControlC : ConsoleSpecialKey.ControlBreak;
     ControlCDelegateData state = new ControlCDelegateData(controlKey, cancelCallbacks);
     WaitCallback callBack = new WaitCallback(Console.ControlCDelegate);
     if (!ThreadPool.QueueUserWorkItem(callBack, state))
     {
         return false;
     }
     TimeSpan timeout = new TimeSpan(0, 0, 30);
     state.CompletionEvent.WaitOne(timeout, false);
     if (!state.DelegateStarted)
     {
         return false;
     }
     state.CompletionEvent.WaitOne();
     state.CompletionEvent.Close();
     return state.Cancel;
 }