def serve_forever(): while True: debug('waiting on next connection') try: handle_next() except (DaemonClosedError, DaemonStoppedError): break debug('done')
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_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')
def ptvsd_subprocess_request(self, request): # When child process is spawned, the notification it sends only # contains information about itself and its immediate parent. # Add information about the root process before passing it on. arguments = dict(request.arguments) arguments.update({ 'rootProcessId': os.getpid(), 'rootStartRequest': root_start_request, }) debug('ptvsd_subprocess: %r' % arguments) response = {'incomingConnection': False} subprocess_queue.put((arguments, response)) subprocess_queue.join() return response
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)')
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 notify_root(port): assert options.subprocess_of debug('Subprocess %d notifying root process at port %d' % (os.getpid(), options.subprocess_notify)) conn = create_client() conn.connect(('localhost', options.subprocess_notify)) stream = JsonIOStream.from_socket(conn) channel = JsonMessageChannel(stream) channel.start() # Send the notification about ourselves to root, and wait for it to tell us # whether an incoming connection is anticipated. This will be true if root # had successfully propagated the notification to the IDE, and false if it # couldn't do so (e.g. because the IDE is not attached). There's also the # possibility that connection to root will just drop, e.g. if it crashes - # in that case, just exit immediately. request = channel.send_request( 'ptvsd_subprocess', { 'parentProcessId': options.subprocess_of, 'processId': os.getpid(), 'port': port, }) try: response = request.wait_for_response() except Exception: print('Failed to send subprocess notification; exiting', file=sys.__stderr__) traceback.print_exc() sys.exit(0) # Keep the channel open until we exit - root process uses open channels to keep # track of which subprocesses are alive and which are not. atexit.register(lambda: channel.close()) if not response['incomingConnection']: debugger = get_global_debugger() while debugger is None: time.sleep(0.1) debugger = get_global_debugger() debugger.ready_to_run = True
def notify_root(port): assert options.subprocess_of debug('Subprocess %d notifying root process at port %d' % (os.getpid(), options.subprocess_notify)) conn = create_client() conn.connect(('localhost', options.subprocess_notify)) stream = JsonIOStream.from_socket(conn) channel = JsonMessageChannel(stream) channel.start() # Send the notification about ourselves to root, and wait for it to tell us # whether an incoming connection is anticipated. This will be true if root # had successfully propagated the notification to the IDE, and false if it # couldn't do so (e.g. because the IDE is not attached). There's also the # possibility that connection to root will just drop, e.g. if it crashes - # in that case, just exit immediately. request = channel.send_request('ptvsd_subprocess', { 'parentProcessId': options.subprocess_of, 'processId': os.getpid(), 'port': port, }) try: response = request.wait_for_response() except Exception: print('Failed to send subprocess notification; exiting', file=sys.__stderr__) traceback.print_exc() sys.exit(0) # Keep the channel open until we exit - root process uses open channels to keep # track of which subprocesses are alive and which are not. atexit.register(lambda: channel.close()) if not response['incomingConnection']: debugger = get_global_debugger() while debugger is None: time.sleep(0.1) debugger = get_global_debugger() debugger.ready_to_run = True
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')
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