Exemple #1
0
    def __init__(self, sock):
        from ptvsd.adapter import sessions

        self.server = None
        """The Server component, if this debug server belongs to Session.
        """

        self.pid = None

        stream = messaging.JsonIOStream.from_socket(sock, str(self))
        self.channel = messaging.JsonMessageChannel(stream, self)
        self.channel.start()

        try:
            info = self.channel.request("pydevdSystemInfo")
            process_info = info("process", json.object())
            self.pid = process_info("pid", int)
            self.ppid = process_info("ppid", int, optional=True)
            if self.ppid == ():
                self.ppid = None

            self.channel.name = stream.name = str(self)
            with _lock:
                if any(conn.pid == self.pid for conn in _connections):
                    raise KeyError(
                        fmt("{0} is already connected to this adapter", self))
                _connections.append(self)
                _connections_changed.set()

        except Exception:
            log.exception("Failed to accept incoming server connection:")
            # If we couldn't retrieve all the necessary info from the debug server,
            # or there's a PID clash, we don't want to track this debuggee anymore,
            # but we want to continue accepting connections.
            self.channel.close()
            return

        parent_session = sessions.get(self.ppid)
        if parent_session is None:
            log.info("No active debug session for parent process of {0}.",
                     self)
        else:
            try:
                parent_session.ide.notify_of_subprocess(self)
            except Exception:
                # This might fail if the IDE concurrently disconnects from the parent
                # session. We still want to keep the connection around, in case the
                # IDE reconnects later. If the parent session was "launch", it'll take
                # care of closing the remaining server connections.
                log.exception("Failed to notify parent session about {0}:",
                              self)
Exemple #2
0
    def __init__(self, sock):
        from ptvsd.adapter import sessions

        self.disconnected = False

        self.server = None
        """The Server component, if this debug server belongs to Session.
        """

        self.pid = None

        stream = messaging.JsonIOStream.from_socket(sock, str(self))
        self.channel = messaging.JsonMessageChannel(stream, self)
        self.channel.start()

        try:
            self.authenticate()
            info = self.channel.request("pydevdSystemInfo")
            process_info = info("process", json.object())
            self.pid = process_info("pid", int)
            self.ppid = process_info("ppid", int, optional=True)
            if self.ppid == ():
                self.ppid = None
            self.channel.name = stream.name = str(self)

            ptvsd_dir = os.path.dirname(os.path.dirname(ptvsd.__file__))
            # Note: we must check if 'ptvsd' is not already in sys.modules because the
            # evaluation of an import at the wrong time could deadlock Python due to
            # its import lock.
            #
            # So, in general this evaluation shouldn't do anything. It's only
            # important when pydevd attaches automatically to a subprocess. In this
            # case, we have to make sure that ptvsd is properly put back in the game
            # for users to be able to use it.v
            #
            # In this case (when the import is needed), this evaluation *must* be done
            # before the configurationDone request is sent -- if this is not respected
            # it's possible that pydevd already started secondary threads to handle
            # commands, in which case it's very likely that this command would be
            # evaluated at the wrong thread and the import could potentially deadlock
            # the program.
            #
            # Note 2: the sys module is guaranteed to be in the frame globals and
            # doesn't need to be imported.
            inject_ptvsd = """
if 'ptvsd' not in sys.modules:
    sys.path.insert(0, {ptvsd_dir!r})
    try:
        import ptvsd
    finally:
        del sys.path[0]
"""
            inject_ptvsd = fmt(inject_ptvsd, ptvsd_dir=ptvsd_dir)

            try:
                self.channel.request("evaluate", {"expression": inject_ptvsd})
            except messaging.MessageHandlingError:
                # Failure to inject is not a fatal error - such a subprocess can
                # still be debugged, it just won't support "import ptvsd" in user
                # code - so don't terminate the session.
                log.exception("Failed to inject ptvsd into {0}:",
                              self,
                              level="warning")

            with _lock:
                # The server can disconnect concurrently before we get here, e.g. if
                # it was force-killed. If the disconnect() handler has already run,
                # don't register this server or report it, since there's nothing to
                # deregister it.
                if self.disconnected:
                    return

                if any(conn.pid == self.pid for conn in _connections):
                    raise KeyError(
                        fmt("{0} is already connected to this adapter", self))
                _connections.append(self)
                _connections_changed.set()

        except Exception:
            log.exception("Failed to accept incoming server connection:")
            self.channel.close()

            # If this was the first server to connect, and the main thread is inside
            # wait_until_disconnected(), we want to unblock it and allow it to exit.
            dont_wait_for_first_connection()

            # If we couldn't retrieve all the necessary info from the debug server,
            # or there's a PID clash, we don't want to track this debuggee anymore,
            # but we want to continue accepting connections.
            return

        parent_session = sessions.get(self.ppid)
        if parent_session is None:
            log.info("No active debug session for parent process of {0}.",
                     self)
        else:
            try:
                parent_session.ide.notify_of_subprocess(self)
            except Exception:
                # This might fail if the IDE concurrently disconnects from the parent
                # session. We still want to keep the connection around, in case the
                # IDE reconnects later. If the parent session was "launch", it'll take
                # care of closing the remaining server connections.
                log.exception("Failed to notify parent session about {0}:",
                              self)