Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"evaluate" should allow nested messages #326

Closed
fabioz opened this issue Jul 5, 2020 · 2 comments
Closed

"evaluate" should allow nested messages #326

fabioz opened this issue Jul 5, 2020 · 2 comments

Comments

@fabioz
Copy link
Collaborator

fabioz commented Jul 5, 2020

This is actually a part of #157 (but this part needs to be solved in the adapter).

I'm up to the point where the part of unblocking threads works in the pydevd side, but I've gotten into some corner cases if during the evaluation another breakpoint is hit in another thread while still answering the evaluation.

Consider the case below where a processor just keeps on echoing what is sent to it (just acknowledging it in obj.event.set(), which the client waits for):

import threading
try:
    from queue import Queue
except:
    from Queue import Queue

class EchoThread(threading.Thread):

    def __init__(self, queue):
        threading.Thread.__init__(self)
        self._queue = queue

    def run(self):
        while True:
            obj = self._queue.get()
            if obj == 'finish':
                break

            print('processed', obj.value)
            obj.event.set()  # break 2

class NotificationObject(object):

    def __init__(self, value):
        self.value = value
        self.event = threading.Event()

class Processor(object):

    def __init__(self, queue):
        self._queue = queue

    def process(self, i):
        obj = NotificationObject(i)
        self._queue.put(obj)
        assert obj.event.wait()

    def finish(self):
        self._queue.put('finish')

if __name__ == '__main__':
    queue = Queue()
    echo_thread = EchoThread(queue)
    processor = Processor(queue)
    echo_thread.start()

    processor.process(1)  # break 1
    processor.process(2)
    processor.process(3)
    processor.finish()
    print('Finished')

Now, consider that there are breakpoints in break 1 and break 2. With the fix I have, when the user does an evaluation for processor.process('something') while stopped in break 1, it'll (after a timeout) proceed to let other threads run and do the evaluation.

Now, in this case, everything works if there are no other breakpoints hit, but in the example, the user has a break 2 on the processor thread, so, pydevd sends a notification to the client saying that a breakpoint was hit (still before returning the evaluate response) and then, all communication from VSCode<->adapter<->pydevd seems to stop.

By doing a thread dump, it appears that the reason this happens is that the adapter stops everything unil some response is given (and as in this case, the breakpoint was hit during the evaluate, everything stays halted inside the adapter).

From a thread dump (thread_dump.txt), it appears the thread Thread Client[1] message handler is blocked in a wait_for_response and due to that everything is halted (i.e.: the stopped event from pydevd doesn't seem to get to VSCode and a continue from VSCode doesn't get to pydevd).

@int19h
Copy link
Contributor

int19h commented Jul 5, 2020

Yep, the design is intentionally serialized by default to simplify implementation - we had a lot of trouble properly synchronizing the fully async response handling in ptvsd 4. Where needed, it has to be done on a case-by-case basis, as with "launch" / "attach" (to allow for "initialized" and "configurationDone"). Sounds like it also needs to be done for "evaluate".

@int19h int19h changed the title debugpy should not block if a response isn't sent in a timely manner "evaluate" should allow nested messages Jul 5, 2020
@fabioz
Copy link
Collaborator Author

fabioz commented Jul 9, 2020

Note: I've actually done this as a part of #157, so, I'm closing this issue as it'll come along with that one.

@fabioz fabioz closed this as completed Jul 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants