예제 #1
0
        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);
            }
        }
예제 #2
0
        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);
            }
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
        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);
            }
        }
예제 #5
0
        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);
            }
        }
예제 #6
0
        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);
            }
        }
예제 #7
0
        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);
            }
        }
예제 #8
0
        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);
            }
        }
예제 #9
0
        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);
            }
        }
예제 #10
0
        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);
            }
        }
예제 #11
0
        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);
            }
        }