|
92 | 92 | import itertools
|
93 | 93 | import traceback
|
94 | 94 | import linecache
|
| 95 | +import selectors |
95 | 96 | import _colorize
|
96 | 97 |
|
97 | 98 | from contextlib import closing
|
@@ -2906,6 +2907,8 @@ class _PdbClient:
|
2906 | 2907 | def __init__(self, pid, server_socket, interrupt_script):
|
2907 | 2908 | self.pid = pid
|
2908 | 2909 | self.read_buf = b""
|
| 2910 | + self.signal_read = None |
| 2911 | + self.signal_write = None |
2909 | 2912 | self.server_socket = server_socket
|
2910 | 2913 | self.interrupt_script = interrupt_script
|
2911 | 2914 | self.pdb_instance = Pdb()
|
@@ -2958,13 +2961,39 @@ def _send(self, **kwargs):
|
2958 | 2961 | self.write_failed = True
|
2959 | 2962 |
|
2960 | 2963 | def _readline(self):
|
2961 |
| - while b"\n" not in self.read_buf: |
2962 |
| - self.read_buf += self.server_socket.recv(16 * 1024) |
2963 |
| - if not self.read_buf: |
2964 |
| - return b"" |
| 2964 | + # Wait for either a SIGINT or a line or EOF from the PDB server. |
| 2965 | + selector = selectors.DefaultSelector() |
| 2966 | + selector.register(self.signal_read, selectors.EVENT_READ) |
| 2967 | + selector.register(self.server_socket, selectors.EVENT_READ) |
| 2968 | + |
| 2969 | + old_wakeup_fd = signal.set_wakeup_fd( |
| 2970 | + self.signal_write.fileno(), |
| 2971 | + warn_on_full_buffer=False, |
| 2972 | + ) |
2965 | 2973 |
|
2966 |
| - ret, sep, self.read_buf = self.read_buf.partition(b"\n") |
2967 |
| - return ret + sep |
| 2974 | + got_sigint = False |
| 2975 | + def sigint_handler(*args, **kwargs): |
| 2976 | + nonlocal got_sigint |
| 2977 | + got_sigint = True |
| 2978 | + |
| 2979 | + old_handler = signal.signal(signal.SIGINT, sigint_handler) |
| 2980 | + try: |
| 2981 | + while b"\n" not in self.read_buf: |
| 2982 | + for key, _ in selector.select(): |
| 2983 | + if key.fileobj == self.signal_read: |
| 2984 | + self.signal_read.recv(1024) |
| 2985 | + if got_sigint: |
| 2986 | + raise KeyboardInterrupt |
| 2987 | + elif key.fileobj == self.server_socket: |
| 2988 | + self.read_buf += self.server_socket.recv(16 * 1024) |
| 2989 | + if not self.read_buf: |
| 2990 | + return b"" |
| 2991 | + |
| 2992 | + ret, sep, self.read_buf = self.read_buf.partition(b"\n") |
| 2993 | + return ret + sep |
| 2994 | + finally: |
| 2995 | + signal.set_wakeup_fd(old_wakeup_fd) |
| 2996 | + signal.signal(signal.SIGINT, old_handler) |
2968 | 2997 |
|
2969 | 2998 | def read_command(self, prompt):
|
2970 | 2999 | reply = input(prompt)
|
@@ -3055,9 +3084,21 @@ def _handle_sigint(self, handler):
|
3055 | 3084 | signal.pthread_sigmask(signal.SIG_BLOCK, {signal.SIGINT})
|
3056 | 3085 | signal.signal(signal.SIGINT, old_handler)
|
3057 | 3086 |
|
| 3087 | + @contextmanager |
| 3088 | + def _signal_socket_pair(self): |
| 3089 | + self.signal_read, self.signal_write = socket.socketpair() |
| 3090 | + try: |
| 3091 | + with (closing(self.signal_read), closing(self.signal_write)): |
| 3092 | + self.signal_read.setblocking(False) |
| 3093 | + self.signal_write.setblocking(False) |
| 3094 | + yield |
| 3095 | + finally: |
| 3096 | + self.signal_read = self.signal_write = None |
| 3097 | + |
3058 | 3098 | def cmdloop(self):
|
3059 | 3099 | with (
|
3060 | 3100 | self._block_sigint(),
|
| 3101 | + self._signal_socket_pair(), |
3061 | 3102 | self.readline_completion(self.complete),
|
3062 | 3103 | ):
|
3063 | 3104 | while not self.write_failed:
|
|
0 commit comments