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); } }