public virtual async Task AttachReattachInfiniteThreads() { Process p = Process.Start(Version.InterpreterPath, "\"" + TestData.GetPath(@"TestData\DebuggerProject\InfiniteThreads.py") + "\""); try { Thread.Sleep(1000); AutoResetEvent attached = new AutoResetEvent(false); AutoResetEvent detached = new AutoResetEvent(false); for (int i = 0; i < 10; i++) { Console.WriteLine(i); var proc = PythonProcess.Attach(p.Id); proc.ProcessLoaded += (sender, args) => { attached.Set(); }; proc.ProcessExited += (sender, args) => { detached.Set(); }; await proc.StartListeningAsync(); Assert.IsTrue(attached.WaitOne(30000), "Failed to attach within 30s"); await proc.DetachAsync(TimeoutToken()); Assert.IsTrue(detached.WaitOne(30000), "Failed to detach within 30s"); } } finally { DisposeProcess(p); } }
public virtual async Task AttachWithOutputRedirection() { var expectedOutput = new[] { "stdout", "stderr" }; string script = TestData.GetPath(@"TestData\DebuggerProject\AttachOutput.py"); var p = Process.Start(Version.InterpreterPath, "\"" + script + "\""); try { using (var dumpWriter = new MiniDumpWriter(p)) { Thread.Sleep(1000); var proc = PythonProcess.Attach(p.Id, PythonDebugOptions.RedirectOutput); try { var attached = new TaskCompletionSource <bool>(); proc.ProcessLoaded += (sender, args) => { Console.WriteLine("Process loaded"); attached.SetResult(true); }; await proc.StartListeningAsync(); await attached.Task.WithTimeout(20000, "Failed to attach within 20s"); await proc.ResumeAsync(TimeoutToken()); var bpHit = new TaskCompletionSource <bool>(); PythonThread thread = null; proc.BreakpointHit += (sender, args) => { thread = args.Thread; bpHit.SetResult(true); }; var bp = proc.AddBreakpoint(script, 5); await bp.AddAsync(TimeoutToken()); await bpHit.Task.WithTimeout(20000, "Failed to hit breakpoint within 20s"); Assert.IsNotNull(thread); var actualOutput = new List <string>(); proc.DebuggerOutput += (sender, e) => { Console.WriteLine("Debugger output: '{0}'", e.Output); actualOutput.Add(e.Output); }; var frame = thread.Frames[0]; Assert.AreEqual("False", (await frame.ExecuteTextAsync("attached", ct: CancellationTokens.After15s)).StringRepr); await frame.ExecuteTextAsync("attached = True", ct : TimeoutToken()); await proc.ResumeAsync(TimeoutToken()); WaitForExit(proc); AssertUtil.ArrayEquals(expectedOutput, actualOutput); } finally { await DetachProcessAsync(proc); } dumpWriter.Cancel(); } } finally { DisposeProcess(p); } }
public virtual async Task AttachSingleThreadedSleeper() { // http://pytools.codeplex.com/discussions/285741 1/12/2012 6:20 PM Process p = Process.Start(Version.InterpreterPath, "\"" + TestData.GetPath(@"TestData\DebuggerProject\AttachSingleThreadedSleeper.py") + "\""); try { Thread.Sleep(1000); AutoResetEvent attached = new AutoResetEvent(false); var proc = PythonProcess.Attach(p.Id); try { proc.ProcessLoaded += (sender, args) => { attached.Set(); }; await proc.StartListeningAsync(); Assert.IsTrue(attached.WaitOne(10000), "Failed to attach within 10s"); await proc.ResumeAsync(TimeoutToken()); Debug.WriteLine("Waiting for exit"); } finally { TerminateProcess(proc); } } finally { DisposeProcess(p); } }
public virtual async Task AttachSingleThreadedSleeper() { // http://pytools.codeplex.com/discussions/285741 1/12/2012 6:20 PM Process p = Process.Start(Version.InterpreterPath, "\"" + TestData.GetPath(@"TestData\DebuggerProject\AttachSingleThreadedSleeper.py") + "\""); try { Thread.Sleep(1000); var attached = new TaskCompletionSource <bool>(); var proc = PythonProcess.Attach(p.Id); try { proc.ProcessLoaded += (sender, args) => { attached.SetResult(true); }; await proc.StartListeningAsync(); using (var dumpWriter = new MiniDumpWriter(p)) { await attached.Task.WithTimeout(10000, "Failed to attach within 10s"); await proc.ResumeAsync(TimeoutToken()); Debug.WriteLine("Waiting for exit"); dumpWriter.Cancel(); } } finally { TerminateProcess(proc); } } finally { DisposeProcess(p); } }
private async Task AttachTestTimeoutAsync(string hostCode) { var exe = CompileCode(hostCode); // start the test process w/ our handle var eventName = Guid.NewGuid().ToString(); EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName); ProcessStartInfo psi = new ProcessStartInfo(exe, eventName); psi.UseShellExecute = false; psi.RedirectStandardError = psi.RedirectStandardOutput = true; psi.CreateNoWindow = true; // Add Python to PATH so that the host can locate the DLL in case it's not in \Windows\System32 (e.g. for EPD) psi.EnvironmentVariables["PATH"] = Environment.GetEnvironmentVariable("PATH") + ";" + Path.GetDirectoryName(Version.InterpreterPath); Process p = Process.Start(psi); var outRecv = new OutputReceiver(); p.OutputDataReceived += outRecv.OutputDataReceived; p.ErrorDataReceived += outRecv.OutputDataReceived; p.BeginErrorReadLine(); p.BeginOutputReadLine(); try { bool isAttached = false; // start the attach with the GIL held AutoResetEvent attachStarted = new AutoResetEvent(false); AutoResetEvent attachDone = new AutoResetEvent(false); // We run the Attach and StartListeningAsync on a separate thread, // because StartListeningAsync waits until debuggee has connected // back (which it won't do until handle is set). var task = Task.Run(async() => { var proc = PythonProcess.Attach(p.Id); try { proc.ProcessLoaded += (sender, args) => { attachDone.Set(); isAttached = false; }; attachStarted.Set(); await proc.StartListeningAsync(10000); } finally { await DetachProcessAsync(proc); } }); Assert.IsTrue(attachStarted.WaitOne(10000), "Failed to start attaching within 10s"); Assert.IsFalse(isAttached, "should not have attached yet"); // we should be blocked handle.Set(); // let the code start running Assert.IsTrue(attachDone.WaitOne(10000), "Failed to attach within 10s"); } finally { Debug.WriteLine(String.Format("Process output: {0}", outRecv.Output.ToString())); DisposeProcess(p); } }
public virtual async Task AttachAndStepWithBlankSysPrefix() { string script = TestData.GetPath(@"TestData\DebuggerProject\InfiniteRunBlankPrefix.py"); var p = Process.Start(Version.InterpreterPath, "\"" + script + "\""); try { using (var dumpWriter = new MiniDumpWriter(p)) { Thread.Sleep(1000); var proc = PythonProcess.Attach(p.Id); try { var attached = new TaskCompletionSource <bool>(); proc.ProcessLoaded += async(sender, args) => { Console.WriteLine("Process loaded"); await proc.ResumeAsync(TimeoutToken()); attached.SetResult(true); }; await proc.StartListeningAsync(); await attached.Task.WithTimeout(20000, "Failed to attach within 20s"); var bpHit = new TaskCompletionSource <bool>(); PythonThread thread = null; PythonStackFrame oldFrame = null; proc.BreakpointHit += (sender, args) => { Console.WriteLine("Breakpoint hit"); thread = args.Thread; oldFrame = args.Thread.Frames[0]; bpHit.SetResult(true); }; var bp = proc.AddBreakpoint(script, 6); await bp.AddAsync(TimeoutToken()); await bpHit.Task.WithTimeout(20000, "Failed to hit breakpoint within 20s"); var stepComplete = new TaskCompletionSource <bool>(); PythonStackFrame newFrame = null; proc.StepComplete += (sender, args) => { newFrame = args.Thread.Frames[0]; stepComplete.SetResult(true); }; await thread.StepOverAsync(TimeoutToken()); await stepComplete.Task.WithTimeout(20000, "Failed to complete the step within 20s"); Assert.AreEqual(oldFrame.FileName, newFrame.FileName); Assert.IsTrue(oldFrame.LineNo + 1 == newFrame.LineNo); } finally { await DetachProcessAsync(proc); } dumpWriter.Cancel(); } } finally { DisposeProcess(p); } }
public virtual void AttachWithOutputRedirection() { var expectedOutput = new[] { "stdout", "stderr" }; string script = TestData.GetPath(@"TestData\DebuggerProject\AttachOutput.py"); var p = Process.Start(Version.InterpreterPath, "\"" + script + "\""); try { Thread.Sleep(1000); var proc = PythonProcess.Attach(p.Id, PythonDebugOptions.RedirectOutput); try { var attached = new AutoResetEvent(false); proc.ProcessLoaded += (sender, args) => { Console.WriteLine("Process loaded"); attached.Set(); }; proc.StartListening(); Assert.IsTrue(attached.WaitOne(20000), "Failed to attach within 20s"); proc.Resume(); var bpHit = new AutoResetEvent(false); PythonThread thread = null; proc.BreakpointHit += (sender, args) => { thread = args.Thread; bpHit.Set(); }; var bp = proc.AddBreakPoint(script, 5); bp.Add(); Assert.IsTrue(bpHit.WaitOne(20000), "Failed to hit breakpoint within 20s"); Assert.IsNotNull(thread); var actualOutput = new List <string>(); proc.DebuggerOutput += (sender, e) => { Console.WriteLine("Debugger output: '{0}'", e.Output); actualOutput.Add(e.Output); }; var frame = thread.Frames[0]; Assert.AreEqual("False", frame.ExecuteTextAsync("attached").Result.StringRepr); Assert.IsTrue(frame.ExecuteTextAsync("attached = True").Wait(20000), "Failed to complete evaluation within 20s"); proc.Resume(); WaitForExit(proc); AssertUtil.ArrayEquals(expectedOutput, actualOutput); } finally { DetachProcess(proc); } } finally { DisposeProcess(p); } }
public virtual void AttachAndStepWithBlankSysPrefix() { string script = TestData.GetPath(@"TestData\DebuggerProject\InfiniteRunBlankPrefix.py"); var p = Process.Start(Version.InterpreterPath, "\"" + script + "\""); try { Thread.Sleep(1000); var proc = PythonProcess.Attach(p.Id); try { var attached = new AutoResetEvent(false); proc.ProcessLoaded += (sender, args) => { Console.WriteLine("Process loaded"); proc.Resume(); attached.Set(); }; proc.StartListening(); Assert.IsTrue(attached.WaitOne(20000), "Failed to attach within 20s"); var bpHit = new AutoResetEvent(false); PythonThread thread = null; PythonStackFrame oldFrame = null; proc.BreakpointHit += (sender, args) => { Console.WriteLine("Breakpoint hit"); thread = args.Thread; oldFrame = args.Thread.Frames[0]; bpHit.Set(); }; var bp = proc.AddBreakPoint(script, 6); bp.Add(); Assert.IsTrue(bpHit.WaitOne(20000), "Failed to hit breakpoint within 20s"); var stepComplete = new AutoResetEvent(false); PythonStackFrame newFrame = null; proc.StepComplete += (sender, args) => { newFrame = args.Thread.Frames[0]; stepComplete.Set(); }; thread.StepOver(); Assert.IsTrue(stepComplete.WaitOne(20000), "Failed to complete the step within 20s"); Assert.AreEqual(oldFrame.FileName, newFrame.FileName); Assert.IsTrue(oldFrame.LineNo + 1 == newFrame.LineNo); } finally { DetachProcess(proc); } } finally { DisposeProcess(p); } }
public virtual async Task AttachReattach() { Process p = Process.Start(Version.InterpreterPath, "\"" + TestData.GetPath(@"TestData\DebuggerProject\InfiniteRun.py") + "\""); try { using (var dumpWriter = new MiniDumpWriter(p)) { Thread.Sleep(1000); for (int i = 0; i < 10; i++) { Console.WriteLine(i); var attached = new TaskCompletionSource <bool>(); var detached = new TaskCompletionSource <bool>(); var proc = PythonProcess.Attach(p.Id); proc.ProcessLoaded += (sender, args) => { attached.SetResult(true); }; proc.ProcessExited += (sender, args) => { detached.SetResult(true); }; await proc.StartListeningAsync(20000); await attached.Task.WithTimeout(10000, "Failed to attach within 10s"); await proc.DetachAsync(TimeoutToken()); await detached.Task.WithTimeout(10000, "Failed to detach within 10s"); } dumpWriter.Cancel(); } } finally { DisposeProcess(p); } }
public virtual async Task AttachThreadingStartNewThread() { // http://pytools.codeplex.com/workitem/638 // http://pytools.codeplex.com/discussions/285741#post724014 var psi = new ProcessStartInfo(Version.InterpreterPath, "\"" + TestData.GetPath(@"TestData\DebuggerProject\ThreadingStartNewThread.py") + "\""); psi.WorkingDirectory = TestData.GetPath(@"TestData\DebuggerProject"); psi.EnvironmentVariables["PYTHONPATH"] = @"..\.."; psi.UseShellExecute = false; psi.RedirectStandardOutput = true; psi.RedirectStandardError = true; Process p = Process.Start(psi); try { if (p.WaitForExit(1000)) { Assert.Fail("Process exited"); } var proc = PythonProcess.Attach(p.Id); try { using (var attached = new AutoResetEvent(false)) using (var readyToContinue = new AutoResetEvent(false)) using (var threadBreakpointHit = new AutoResetEvent(false)) { proc.ProcessLoaded += async(sender, args) => { attached.Set(); var bp = proc.AddBreakpoint("ThreadingStartNewThread.py", 9); await bp.AddAsync(TimeoutToken()); bp = proc.AddBreakpoint("ThreadingStartNewThread.py", 5); await bp.AddAsync(TimeoutToken()); await proc.ResumeAsync(TimeoutToken()); }; PythonThread mainThread = null; PythonThread bpThread = null; bool wrongLine = false; proc.BreakpointHit += async(sender, args) => { if (args.Breakpoint.LineNo == 9) { // stop running the infinite loop Debug.WriteLine(String.Format("First BP hit {0}", args.Thread.Id)); mainThread = args.Thread; await args.Thread.Frames[0].ExecuteTextAsync("x = False", (x) => { readyToContinue.Set(); }, TimeoutToken()); } else if (args.Breakpoint.LineNo == 5) { // we hit the breakpoint on the new thread Debug.WriteLine(String.Format("Second BP hit {0}", args.Thread.Id)); bpThread = args.Thread; threadBreakpointHit.Set(); await proc.ResumeAsync(TimeoutToken()); } else { Debug.WriteLine(String.Format("Hit breakpoint on wrong line number: {0}", args.Breakpoint.LineNo)); wrongLine = true; attached.Set(); threadBreakpointHit.Set(); await proc.ResumeAsync(TimeoutToken()); } }; await proc.StartListeningAsync(); Assert.IsTrue(attached.WaitOne(30000), "Failed to attach within 30s"); Assert.IsTrue(readyToContinue.WaitOne(30000), "Failed to hit the main thread breakpoint within 30s"); await proc.ResumeAsync(TimeoutToken()); Assert.IsTrue(threadBreakpointHit.WaitOne(30000), "Failed to hit the background thread breakpoint within 30s"); Assert.IsFalse(wrongLine, "Breakpoint broke on the wrong line"); Assert.AreNotEqual(mainThread, bpThread); } } finally { await DetachProcessAsync(proc); } } finally { DisposeProcess(p); } }
public virtual async Task AttachNewThread_PyThreadState_New() { var hostCode = @"#include <Windows.h> #include <process.h> #include <Python.h> PyObject *g_pFunc; void Thread(void*) { printf(""Worker thread started %x\r\n"", GetCurrentThreadId()); while (true) { PyEval_AcquireLock(); PyInterpreterState* pMainInterpreterState = PyInterpreterState_Head(); auto pThisThreadState = PyThreadState_New(pMainInterpreterState); PyThreadState_Swap(pThisThreadState); PyObject *pValue; pValue = PyObject_CallObject(g_pFunc, 0); if (pValue != NULL) { //printf(""Result of call: %ld\n"", PyInt_AsLong(pValue)); Py_DECREF(pValue); } else { PyErr_Print(); return; } PyThreadState_Swap(NULL); PyThreadState_Clear(pThisThreadState); PyThreadState_Delete(pThisThreadState); PyEval_ReleaseLock(); Sleep(1000); } } void main() { PyObject *pName, *pModule; Py_SetPythonHome($PYTHON_HOME); Py_Initialize(); PyEval_InitThreads(); pName = CREATE_STRING(""gilstate_attach""); pModule = PyImport_Import(pName); Py_DECREF(pName); if (pModule != NULL) { g_pFunc = PyObject_GetAttrString(pModule, ""test""); if (g_pFunc && PyCallable_Check(g_pFunc)) { DWORD threadID; threadID = _beginthread(&Thread, 1024*1024, 0); threadID = _beginthread(&Thread, 1024*1024, 0); PyEval_ReleaseLock(); while (true); } else { if (PyErr_Occurred()) PyErr_Print(); } Py_XDECREF(g_pFunc); Py_DECREF(pModule); } else { PyErr_Print(); return; } Py_Finalize(); return; }".Replace("CREATE_STRING", CreateString); var exe = CompileCode(hostCode); File.WriteAllText(Path.Combine(Path.GetDirectoryName(exe), "gilstate_attach.py"), @"def test(): for i in range(10): print(i) return 0"); // start the test process w/ our handle Process p = RunHost(exe); try { Thread.Sleep(1500); AutoResetEvent attached = new AutoResetEvent(false); AutoResetEvent bpHit = new AutoResetEvent(false); var proc = PythonProcess.Attach(p.Id); try { proc.ProcessLoaded += (sender, args) => { Console.WriteLine("Process loaded"); attached.Set(); }; await proc.StartListeningAsync(); Assert.IsTrue(attached.WaitOne(20000), "Failed to attach within 20s"); proc.BreakpointHit += (sender, args) => { Console.WriteLine("Breakpoint hit"); bpHit.Set(); }; var bp = proc.AddBreakpoint("gilstate_attach.py", 3); await bp.AddAsync(TimeoutToken()); Assert.IsTrue(bpHit.WaitOne(20000), "Failed to hit breakpoint within 20s"); } finally { await DetachProcessAsync(proc); } } finally { DisposeProcess(p); } }