public bool ManagedCallback(ManagedCallbackFunction func, CommandResult result)
        {
            ManagedCallbackData data = new ManagedCallbackData (func, result);

            return (bool) SendCommand (delegate {
                Report.Debug (DebugFlags.SSE, "{0} starting managed callback: {1}", this, func);

                AcquireThreadLock ();

                if (is_managed_frame ()) {
                    //
                    // We found a managed frame; now let's first check whether we can do
                    // all the work without starting an operation.
                    //
                    OperationManagedCallback omc = new OperationManagedCallback (this, data);
                    if (omc.Run ())
                        return false;

                    //
                    // Ok, we're done -> return to the user.
                    //

                    ReleaseThreadLock ();
                    return true;
                }

                //
                // Stop all threads and check whether one of them is in managed land.
                //

                Report.Debug (DebugFlags.SSE, "{0} managed callback needs global thread lock", this);

                bool ok = false;
                process.AcquireGlobalThreadLock (this);
                foreach (SingleSteppingEngine engine in process.ThreadServants) {
                    try {
                        if (engine.is_managed_frame ()) {
                            ok = true;
                            break;
                        }
                    } catch (Exception ex) {
                        Console.WriteLine ("F**K: {0} {1}", engine, ex);
                    }
                }

                if (!ok) {
                    //
                    // None of the threads is currently in managed land; request a managed
                    // callback.
                    //
                    request_managed_callback (data);
                }

                Report.Debug (DebugFlags.SSE, "{0} managed callback releasing global thread lock", this);
                process.ReleaseGlobalThreadLock (this);

                ReleaseThreadLock ();

                Report.Debug (DebugFlags.SSE, "{0} managed callback done: {1} {2}", this, data.Running, data.Completed);
                return false;
            });
        }
 public OperationManagedCallback(SingleSteppingEngine sse, ManagedCallbackData data)
     : base(sse, null)
 {
     CallbackFunctions = new Queue<ManagedCallbackData> ();
     CallbackFunctions.Enqueue (data);
 }
            bool do_execute()
            {
                Report.Debug (DebugFlags.SSE, "{0} managed callback execute start: {1}", sse, CallbackFunctions.Count);

                while (CallbackFunctions.Count > 0) {
                current_callback = CallbackFunctions.Dequeue ();
                Report.Debug (DebugFlags.SSE, "{0} managed callback execute: {1}",
                          sse, current_callback.Func);
                current_callback.Running = true;
                bool running = current_callback.Func (sse);
                Report.Debug (DebugFlags.SSE, "{0} managed callback execute done: {1} {2}",
                          sse, current_callback.Func, running);
                if (running)
                    return true;

                current_callback.Completed = true;

                current_callback.Result.Completed ();
                }

                return false;
            }
        void request_managed_callback(ManagedCallbackData data)
        {
            TargetAddress lmf_address = inferior.ReadAddress (LMFAddress);
            StackFrame lmf_frame = Architecture.GetLMF (this, inferior, ref lmf_address);

            Report.Debug (DebugFlags.SSE, "{0} requesting managed callback: {1}", this, lmf_frame);
            process.MonoManager.AddManagedCallback (inferior, data);

            /*
             * Prevent a race condition:
             * If we stopped just before returning from native code,
             * mono_thread_interruption_checkpoint_request() may not be called again
             * before returning back to managed code; it's called next time we're entering
             * native code again.
             *
             * This could lead to problems if the managed code does some CPU-intensive
             * before going unmanaged next time - or even loops forever.
             *
             * I have a test case where an icall contains a sleep() and the managed code
             * contains an infinite loop (`for (;;) ;) immediately after returning from
             * this icall.
             *
             * To prevent this from happening, we insert a breakpoint on the last managed
             * frame.
             */

            if (lmf_frame != null)
                insert_lmf_breakpoint (lmf_frame.TargetAddress);
            else {
                Report.Error ("{0} unable to compute LMF for managed callback: {1}",
                          this, inferior.CurrentFrame);
            }
        }