def listen_for_subprocesses(): """Starts a listener for incoming 'ptvsd_subprocess' notifications that enqueues them in subprocess_queue. """ global subprocess_listener_socket assert subprocess_listener_socket is None subprocess_listener_socket = create_server('localhost', 0) atexit.register(stop_listening_for_subprocesses) new_hidden_thread('SubprocessListener', _subprocess_listener).start()
def listen_for_subprocesses(): """Starts a listener for incoming 'ptvsd_subprocess' notifications that enqueues them in subprocess_queue. """ global subprocess_listener_socket assert subprocess_listener_socket is None subprocess_listener_socket = create_server('localhost', 0) atexit.register(stop_listening_for_subprocesses) new_hidden_thread('SubprocessListener', _subprocess_listener).start()
def debug_main(address, name, kind, *extra, **kwargs): if not kwargs.pop('wait', False) and address.isserver: def unblock_debugger(): debugger = get_global_debugger() while debugger is None: time.sleep(0.1) debugger = get_global_debugger() debugger.ready_to_run = True new_hidden_thread('ptvsd.unblock_debugger', unblock_debugger).start() if kind == 'module': run_module(address, name, *extra, **kwargs) else: run_file(address, name, *extra, **kwargs)
def debug_main(address, name, kind, *extra, **kwargs): if not kwargs.pop('wait', False) and address.isserver: def unblock_debugger(): debugger = get_global_debugger() while debugger is None: time.sleep(0.1) debugger = get_global_debugger() debugger.ready_to_run = True new_hidden_thread('ptvsd.unblock_debugger', unblock_debugger).start() if kind == 'module': run_module(address, name, *extra, **kwargs) else: run_file(address, name, *extra, **kwargs)
def enable_attach(address, redirect_output=True, _pydevd=pydevd, _install=install, on_attach=lambda: None, **kwargs): ptvsd.main_thread = threading.current_thread() host, port = address def wait_for_connection(daemon, host, port, next_session=None): ptvsd.log.debug('Waiting for pydevd ...') debugger = get_global_debugger() while debugger is None: time.sleep(0.1) debugger = get_global_debugger() ptvsd.log.debug('Unblocking pydevd.') debugger.ready_to_run = True while True: session_not_bound.wait() try: global_next_session() on_attach() except DaemonClosedError: return def start_daemon(): daemon._sock = daemon._start() _, next_session = daemon.start_server(addr=(host, port)) global global_next_session global_next_session = next_session return daemon._sock daemon = _install(_pydevd, address, start_server=None, start_client=(lambda daemon, h, port: start_daemon()), singlesession=False, **kwargs) ptvsd.log.debug('Starting connection listener thread') connection_thread = new_hidden_thread('ptvsd.listen_for_connection', wait_for_connection, args=(daemon, host, port)) connection_thread.start() if ptvsd.options.no_debug: _setup_nodebug() else: ptvsd.log.debug('pydevd.settrace()') _pydevd.settrace(host=host, stdoutToServer=redirect_output, stderrToServer=redirect_output, port=port, suspend=False, patch_multiprocessing=ptvsd.options.multiprocess) return daemon
def enable_attach(address, redirect_output=True, _pydevd=pydevd, _install=install, on_attach=lambda: None, **kwargs): ptvsd.main_thread = threading.current_thread() host, port = address def wait_for_connection(daemon, host, port, next_session=None): ptvsd.log.debug('Waiting for pydevd ...') debugger = get_global_debugger() while debugger is None: time.sleep(0.1) debugger = get_global_debugger() ptvsd.log.debug('Unblocking pydevd.') debugger.ready_to_run = True while True: session_not_bound.wait() try: global_next_session() on_attach() except DaemonClosedError: return def start_daemon(): daemon._sock = daemon._start() _, next_session = daemon.start_server(addr=(host, port)) global global_next_session global_next_session = next_session return daemon._sock daemon = _install(_pydevd, address, start_server=None, start_client=(lambda daemon, h, port: start_daemon()), singlesession=False, **kwargs) ptvsd.log.debug('Starting connection listener thread') connection_thread = new_hidden_thread('ptvsd.listen_for_connection', wait_for_connection, args=(daemon, host, port)) connection_thread.start() if ptvsd.options.no_debug: _setup_nodebug() else: ptvsd.log.debug('pydevd.settrace()') _pydevd.settrace(host=host, stdoutToServer=redirect_output, stderrToServer=redirect_output, port=port, suspend=False, patch_multiprocessing=ptvsd.options.multiprocess) return daemon
def _start_event_loop(self): self.loop = futures.EventLoop() self.event_loop_thread = _util.new_hidden_thread( target=self.loop.run_forever, name='EventLoop', ) self.event_loop_thread.start()
def _handle_connected(self): # TODO: make it a daemon thread? self._listener = new_hidden_thread( target=self._listen, name='test.msgdaemon', daemon=False, ) self._listener.start()
def enable_attach(address, on_attach=(lambda: None), redirect_output=True, _pydevd=pydevd, _install=install, _settrace=_pydevd_settrace, **kwargs): addr = Address.as_server(*address) debug('installing ptvsd as server') # pydevd.settrace() forces a "client" connection, so we trick it # by setting start_client to start_server.. daemon = _install(_pydevd, addr, start_client=start_server, notify_session_debugger_ready=(lambda s: on_attach()), singlesession=False, **kwargs) def start_pydevd(): debug('enabling pydevd') # Only pass the port so start_server() gets triggered. # As noted above, we also have to trick settrace() because it # *always* forces a client connection. _settrace( stdoutToServer=redirect_output, stderrToServer=redirect_output, port=addr.port, suspend=False, _pydevd=_pydevd, ) debug('pydevd enabled') t = new_hidden_thread('start-pydevd', start_pydevd) t.start() def wait(timeout=None): t.join(timeout) return not t.is_alive() def debug_current_thread(suspend=False, **kwargs): # Make sure that pydevd has finished starting before enabling # in the current thread. t.join() debug('enabling pydevd (current thread)') _settrace( host=None, # ignored stdoutToServer=False, # ignored stderrToServer=False, # ignored port=None, # ignored suspend=suspend, trace_only_current_thread=True, overwrite_prev_trace=True, patch_multiprocessing=False, _pydevd=_pydevd, **kwargs) debug('pydevd enabled (current thread)') return daemon, wait, debug_current_thread
def start(self): if self._server is not None: raise RuntimeError('already started') self._server = HTTPServer(self._addr, self.handler) self._thread = new_hidden_thread( target=(lambda: self._server.serve_forever()), name='test.http', ) self._thread.start()
def enable_attach(address, on_attach=lambda: None, **kwargs): host, port = address def wait_for_connection(daemon, host, port, next_session=None): ptvsd.log.debug('Waiting for pydevd ...') debugger = get_global_debugger() while debugger is None: time.sleep(0.1) debugger = get_global_debugger() ptvsd.log.debug('Unblocking pydevd.') debugger.ready_to_run = True while True: try: session_not_bound.wait() try: global_next_session() on_attach() except DaemonClosedError: return except TypeError: # May happen during interpreter shutdown # (if some global -- such as global_next_session becomes None). return def start_daemon(): daemon._sock = daemon._start() _, next_session = daemon.start_server(addr=(host, port)) global global_next_session global_next_session = next_session return daemon._sock daemon = install(pydevd, address, start_server=None, start_client=(lambda daemon, h, port: start_daemon()), singlesession=False, **kwargs) ptvsd.log.debug('Starting connection listener thread') connection_thread = new_hidden_thread('ptvsd.listen_for_connection', wait_for_connection, args=(daemon, host, port)) connection_thread.start() if ptvsd.options.no_debug: _setup_nodebug() else: ptvsd.log.debug('pydevd.settrace()') pydevd.settrace(host=host, port=port, suspend=False, patch_multiprocessing=ptvsd.options.multiprocess) return daemon
def __init__(self, stream, handlers=None, name=None): self.stream = stream self.name = name if name is not None else stream.name self._lock = threading.Lock() self._stop = threading.Event() self._seq_iter = itertools.count(1) self._requests = {} self._handlers = handlers self._worker = new_hidden_thread('{} message channel worker'.format(self.name), self._process_incoming_messages) self._worker.daemon = True
def _start(self, address): connect, addr = self._bind(address) def run(): self._sock = connect() self._handle_connected() t = new_hidden_thread( target=run, name='test.daemon', ) t.start() return addr, t
def host_local_debugger(self, argv, script=None, env=None, cwd=None, **kwargs): # noqa if self.closed: raise RuntimeError('debug client closed') if self._adapter is not None: raise RuntimeError('debugger already running') assert self._session is None addr = ('localhost', self._addr.port) self._run_server_ex = None def run(): try: self._session = self.SESSION.create_server(addr, **kwargs) except Exception as ex: self._run_server_ex = traceback.format_exc() t = new_hidden_thread( target=run, name='test.client', ) t.start() def wait(): t.join(timeout=self._connecttimeout) if t.is_alive(): warnings.warn('timed out waiting for connection') if self._session is None: message = 'unable to connect after {} secs'.format( # noqa self._connecttimeout) if self._run_server_ex is None: raise Exception(message) else: message = message + os.linesep + self._run_server_ex # noqa raise Exception(message) # The adapter will close when the connection does. self._launch( argv, script=script, wait_for_connect=wait, detachable=False, env=env, cwd=cwd) return self._adapter, self._session
def enable_attach(address, redirect_output=True, _pydevd=pydevd, _install=install, on_attach=lambda: None, **kwargs): host, port = address def wait_for_connection(daemon, host, port, next_session=None): debugger = get_global_debugger() while debugger is None: time.sleep(0.1) debugger = get_global_debugger() debugger.ready_to_run = True while True: session_not_bound.wait() try: global_next_session() on_attach() except DaemonClosedError: return def start_daemon(): daemon._sock = daemon._start() _, next_session = daemon.start_server(addr=(host, port)) global global_next_session global_next_session = next_session return daemon._sock daemon = _install(_pydevd, address, start_server=None, start_client=(lambda daemon, h, port: start_daemon()), singlesession=False, **kwargs) connection_thread = new_hidden_thread('ptvsd.listen_for_connection', wait_for_connection, args=(daemon, host, port)) connection_thread.start() _pydevd.settrace(host=host, stdoutToServer=redirect_output, stderrToServer=redirect_output, port=port, suspend=False)
def enable_attach(address, redirect_output=True, _pydevd=pydevd, _install=install, on_attach=lambda: None, **kwargs): host, port = address def wait_for_connection(daemon, host, port, next_session=None): debugger = get_global_debugger() while debugger is None: time.sleep(0.1) debugger = get_global_debugger() debugger.ready_to_run = True while True: session_not_bound.wait() try: global_next_session() on_attach() except DaemonClosedError: return def start_daemon(): daemon._sock = daemon._start() _, next_session = daemon.start_server(addr=(host, port)) global global_next_session global_next_session = next_session return daemon._sock daemon = _install(_pydevd, address, start_server=None, start_client=(lambda daemon, h, port: start_daemon()), singlesession=False, **kwargs) connection_thread = new_hidden_thread('ptvsd.listen_for_connection', wait_for_connection, args=(daemon, host, port)) connection_thread.start() _pydevd.settrace(host=host, stdoutToServer=redirect_output, stderrToServer=redirect_output, port=port, suspend=False)
def start_server(daemon, host, port, **kwargs): """Return a socket to a (new) local pydevd-handling daemon. The daemon supports the pydevd client wire protocol, sending requests and handling responses (and events). This is a replacement for _pydevd_bundle.pydevd_comm.start_server. """ sock, next_session = daemon.start_server((host, port)) def handle_next(): try: session = next_session(**kwargs) debug('done waiting') return session except (DaemonClosedError, DaemonStoppedError): # Typically won't happen. debug('stopped') raise except Exception as exc: # TODO: log this? debug('failed:', exc, tb=True) return None while True: debug('waiting on initial connection') handle_next() break def serve_forever(): while True: debug('waiting on next connection') try: handle_next() except (DaemonClosedError, DaemonStoppedError): break debug('done') t = new_hidden_thread( target=serve_forever, name='sessions', ) t.start() return sock
def __init__(self, conn, seq=1000, handlers=(), timeout=None, owned=False): super(DebugSession, self).__init__() self._conn = conn self._seq = seq self._timeout = timeout self._owned = owned self._handlers = [] for handler in handlers: if callable(handler): self._add_handler(handler) else: self._add_handler(*handler) self._received = [] self._listenerthread = new_hidden_thread( target=self._listen, name='test.session', ) self._listenerthread.start()
def start_server(daemon, host, port, **kwargs): """Return a socket to a (new) local pydevd-handling daemon. The daemon supports the pydevd client wire protocol, sending requests and handling responses (and events). This is a replacement for _pydevd_bundle.pydevd_comm.start_server. """ sock, next_session = daemon.start_server((host, port)) def handle_next(): try: ptvsd.log.debug('Waiting for session...') session = next_session(**kwargs) ptvsd.log.debug('Got session') return session except (DaemonClosedError, DaemonStoppedError): # Typically won't happen. ptvsd.log.exception('Daemon stopped while waiting for session', category='D') raise except Exception: ptvsd.log.exception() return None def serve_forever(): ptvsd.log.debug('Waiting for initial connection...') handle_next() while True: ptvsd.log.debug('Waiting for next connection...') try: handle_next() except (DaemonClosedError, DaemonStoppedError): break ptvsd.log.debug('Done serving') t = new_hidden_thread( target=serve_forever, name='sessions', ) t.start() return sock
def start(self, threadname): # event loop self._start_event_loop() # VSC msg processing loop def process_messages(): self.readylock.acquire() with self._connlock: self._listening = threading.Lock() try: self.process_messages() except (EOFError, TimeoutError): ptvsd.log.exception('Client socket closed', category='I') with self._connlock: _util.lock_release(self._listening) _util.lock_release(self._connected) self.close() except socket.error as exc: if exc.errno == errno.ECONNRESET: ptvsd.log.exception('Client socket forcibly closed', category='I') with self._connlock: _util.lock_release(self._listening) _util.lock_release(self._connected) self.close() else: raise exc self.server_thread = _util.new_hidden_thread( target=process_messages, name=threadname, ) self.server_thread.start() # special initialization self.send_event( 'output', category='telemetry', output='ptvsd', data={'version': __version__}, ) self.readylock.release()
def start_server(daemon, host, port, **kwargs): """Return a socket to a (new) local pydevd-handling daemon. The daemon supports the pydevd client wire protocol, sending requests and handling responses (and events). This is a replacement for _pydevd_bundle.pydevd_comm.start_server. """ sock, next_session = daemon.start_server((host, port)) def handle_next(): try: session = next_session(**kwargs) debug('done waiting') return session except (DaemonClosedError, DaemonStoppedError): # Typically won't happen. debug('stopped') raise except Exception as exc: # TODO: log this? debug('failed:', exc, tb=True) return None def serve_forever(): debug('waiting on initial connection') handle_next() while True: debug('waiting on next connection') try: handle_next() except (DaemonClosedError, DaemonStoppedError): break debug('done') t = new_hidden_thread( target=serve_forever, name='sessions', ) t.start() return sock
def start_server(daemon, host, port, **kwargs): """Return a socket to a (new) local pydevd-handling daemon. The daemon supports the pydevd client wire protocol, sending requests and handling responses (and events). This is a replacement for _pydevd_bundle.pydevd_comm.start_server. """ sock, next_session = daemon.start_server((host, port)) def handle_next(): try: ptvsd.log.debug('Waiting for session...') session = next_session(**kwargs) ptvsd.log.debug('Got session') return session except (DaemonClosedError, DaemonStoppedError): # Typically won't happen. ptvsd.log.exception('Daemon stopped while waiting for session', category='D') raise except Exception: ptvsd.log.exception() return None def serve_forever(): ptvsd.log.debug('Waiting for initial connection...') handle_next() while True: ptvsd.log.debug('Waiting for next connection...') try: handle_next() except (DaemonClosedError, DaemonStoppedError): break ptvsd.log.debug('Done serving') t = new_hidden_thread( target=serve_forever, name='sessions', ) t.start() return sock
def collect_lines(stream, buf=None, notify_received=None, **kwargs): # (inspired by https://stackoverflow.com/questions/375427) if buf is None: buf = queue.Queue() if notify_received is None: notify_received = buf.put else: def notify_received(line, _notify=notify_received): _notify(line) buf.put(line) t = new_hidden_thread( target=process_lines, args=(stream, notify_received), kwargs=kwargs, name='test.proc.output', ) t.start() return buf, t
def _stop_daemon(self, daemon, disconnect=True, timeout=10.0): # We must close ptvsd directly (rather than closing the external # socket (i.e. "daemon"). This is because cloing ptvsd blocks, # keeping us from sending the disconnect request we need to send # at the end. t = new_hidden_thread( target=self._fix.close_ptvsd, name='test.lifecycle', ) #with self._fix.wait_for_events(['exited', 'terminated']): if True: # The thread runs close_ptvsd(), which sends the two # events and then waits for a "disconnect" request. We send # that after we receive the events. t.start() if disconnect: self.disconnect() t.join(timeout) if t.isAlive(): raise Exception( '_stop_daemon timed out after {} secs'.format(timeout)) daemon.close()
def handle_debugger_stopped(self, wait=None): """Deal with the debugger exiting.""" # Notify the editor that the debugger has stopped. if not self._debugging: # TODO: Fail? If this gets called then we must be debugging. return # We run this in a thread to allow handle_exiting() to be called # at the same time. def stop(): if wait is not None: wait() # Since pydevd is embedded in the debuggee process, always # make sure the exited event is sent first. self._wait_until_exiting(self.EXITWAIT) self._ensure_debugger_stopped() t = _util.new_hidden_thread( target=stop, name='stopping', daemon=False, ) t.start()
def start_subprocess_notifier(self): self._subprocess_notifier_thread = _util.new_hidden_thread('SubprocessNotifier', self._subprocess_notifier) self._subprocess_notifier_thread.start()