forked from goodboy/tractor
				
			Distinguish between a local pdb unlock and the tty unlock in root
							parent
							
								
									ef89ed947a
								
							
						
					
					
						commit
						be1fcb2a5b
					
				| 
						 | 
					@ -45,7 +45,8 @@ _global_actor_in_debug: Optional[Tuple[str, str]] = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# lock in root actor preventing multi-access to local tty
 | 
					# lock in root actor preventing multi-access to local tty
 | 
				
			||||||
_debug_lock: trio.StrictFIFOLock = trio.StrictFIFOLock()
 | 
					_debug_lock: trio.StrictFIFOLock = trio.StrictFIFOLock()
 | 
				
			||||||
_pdb_complete: Optional[trio.Event] = None
 | 
					_local_pdb_complete: Optional[trio.Event] = None
 | 
				
			||||||
 | 
					_no_remote_has_tty: Optional[trio.Event] = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# XXX: set by the current task waiting on the root tty lock
 | 
					# XXX: set by the current task waiting on the root tty lock
 | 
				
			||||||
# and must be cancelled if this actor is cancelled via message
 | 
					# and must be cancelled if this actor is cancelled via message
 | 
				
			||||||
| 
						 | 
					@ -130,14 +131,15 @@ async def _acquire_debug_lock(uid: Tuple[str, str]) -> AsyncIterator[None]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    task_name = trio.lowlevel.current_task().name
 | 
					    task_name = trio.lowlevel.current_task().name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    log.debug(
 | 
					    log.pdb(
 | 
				
			||||||
        f"Attempting to acquire TTY lock, remote task: {task_name}:{uid}")
 | 
					        f"Attempting to acquire TTY lock, remote task: {task_name}:{uid}"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async with _debug_lock:
 | 
					    async with _debug_lock:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # _debug_lock._uid = uid
 | 
					 | 
				
			||||||
        _global_actor_in_debug = uid
 | 
					        _global_actor_in_debug = uid
 | 
				
			||||||
        log.debug(f"TTY lock acquired, remote task: {task_name}:{uid}")
 | 
					        log.debug(f"TTY lock acquired, remote task: {task_name}:{uid}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        yield
 | 
					        yield
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _global_actor_in_debug = None
 | 
					    _global_actor_in_debug = None
 | 
				
			||||||
| 
						 | 
					@ -162,8 +164,17 @@ async def _hijack_stdin_relay_to_child(
 | 
				
			||||||
    subactor_uid: Tuple[str, str]
 | 
					    subactor_uid: Tuple[str, str]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
) -> str:
 | 
					) -> str:
 | 
				
			||||||
 | 
					    '''Hijack the tty in the root process of an actor tree such that
 | 
				
			||||||
 | 
					    the pdbpp debugger console can be allocated to a sub-actor for repl
 | 
				
			||||||
 | 
					    bossing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    global _pdb_complete
 | 
					    '''
 | 
				
			||||||
 | 
					    global _no_remote_has_tty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # mark the tty lock as being in use so that the runtime
 | 
				
			||||||
 | 
					    # can try to avoid clobbering any connection from a child
 | 
				
			||||||
 | 
					    # that's currently relying on it.
 | 
				
			||||||
 | 
					    _no_remote_has_tty = trio.Event()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    task_name = trio.lowlevel.current_task().name
 | 
					    task_name = trio.lowlevel.current_task().name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -184,7 +195,7 @@ async def _hijack_stdin_relay_to_child(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # indicate to child that we've locked stdio
 | 
					            # indicate to child that we've locked stdio
 | 
				
			||||||
            await ctx.started('Locked')
 | 
					            await ctx.started('Locked')
 | 
				
			||||||
            log.runtime(  # type: ignore
 | 
					            log.pdb(  # type: ignore
 | 
				
			||||||
                f"Actor {subactor_uid} ACQUIRED stdin hijack lock")
 | 
					                f"Actor {subactor_uid} ACQUIRED stdin hijack lock")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # wait for unlock pdb by child
 | 
					        # wait for unlock pdb by child
 | 
				
			||||||
| 
						 | 
					@ -204,6 +215,7 @@ async def _hijack_stdin_relay_to_child(
 | 
				
			||||||
        f"TTY lock released, remote task: {task_name}:{subactor_uid}")
 | 
					        f"TTY lock released, remote task: {task_name}:{subactor_uid}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    log.debug(f"Actor {subactor_uid} RELEASED stdin hijack lock")
 | 
					    log.debug(f"Actor {subactor_uid} RELEASED stdin hijack lock")
 | 
				
			||||||
 | 
					    _no_remote_has_tty.set()
 | 
				
			||||||
    return "pdb_unlock_complete"
 | 
					    return "pdb_unlock_complete"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -228,7 +240,7 @@ async def _breakpoint(
 | 
				
			||||||
    actor = tractor.current_actor()
 | 
					    actor = tractor.current_actor()
 | 
				
			||||||
    task_name = trio.lowlevel.current_task().name
 | 
					    task_name = trio.lowlevel.current_task().name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    global _pdb_complete, _pdb_release_hook
 | 
					    global _local_pdb_complete, _pdb_release_hook
 | 
				
			||||||
    global _local_task_in_debug, _global_actor_in_debug
 | 
					    global _local_task_in_debug, _global_actor_in_debug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def wait_for_parent_stdin_hijack(
 | 
					    async def wait_for_parent_stdin_hijack(
 | 
				
			||||||
| 
						 | 
					@ -260,7 +272,7 @@ async def _breakpoint(
 | 
				
			||||||
                            # TODO: shielding currently can cause hangs...
 | 
					                            # TODO: shielding currently can cause hangs...
 | 
				
			||||||
                            # with trio.CancelScope(shield=True):
 | 
					                            # with trio.CancelScope(shield=True):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            await _pdb_complete.wait()
 | 
					                            await _local_pdb_complete.wait()
 | 
				
			||||||
                            await stream.send('pdb_unlock')
 | 
					                            await stream.send('pdb_unlock')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            # sync with callee termination
 | 
					                            # sync with callee termination
 | 
				
			||||||
| 
						 | 
					@ -275,8 +287,8 @@ async def _breakpoint(
 | 
				
			||||||
                _local_task_in_debug = None
 | 
					                _local_task_in_debug = None
 | 
				
			||||||
                log.debug(f"Child {actor} released parent stdio lock")
 | 
					                log.debug(f"Child {actor} released parent stdio lock")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not _pdb_complete or _pdb_complete.is_set():
 | 
					    if not _local_pdb_complete or _local_pdb_complete.is_set():
 | 
				
			||||||
        _pdb_complete = trio.Event()
 | 
					        _local_pdb_complete = trio.Event()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # TODO: need a more robust check for the "root" actor
 | 
					    # TODO: need a more robust check for the "root" actor
 | 
				
			||||||
    if actor._parent_chan and not is_root_process():
 | 
					    if actor._parent_chan and not is_root_process():
 | 
				
			||||||
| 
						 | 
					@ -291,7 +303,7 @@ async def _breakpoint(
 | 
				
			||||||
            # support for recursive entries to `tractor.breakpoint()`
 | 
					            # support for recursive entries to `tractor.breakpoint()`
 | 
				
			||||||
            log.warning(f"{actor.uid} already has a debug lock, waiting...")
 | 
					            log.warning(f"{actor.uid} already has a debug lock, waiting...")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await _pdb_complete.wait()
 | 
					            await _local_pdb_complete.wait()
 | 
				
			||||||
            await trio.sleep(0.1)
 | 
					            await trio.sleep(0.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # mark local actor as "in debug mode" to avoid recurrent
 | 
					        # mark local actor as "in debug mode" to avoid recurrent
 | 
				
			||||||
| 
						 | 
					@ -299,7 +311,7 @@ async def _breakpoint(
 | 
				
			||||||
        _local_task_in_debug = task_name
 | 
					        _local_task_in_debug = task_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # assign unlock callback for debugger teardown hooks
 | 
					        # assign unlock callback for debugger teardown hooks
 | 
				
			||||||
        _pdb_release_hook = _pdb_complete.set
 | 
					        _pdb_release_hook = _local_pdb_complete.set
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # this **must** be awaited by the caller and is done using the
 | 
					        # this **must** be awaited by the caller and is done using the
 | 
				
			||||||
        # root nursery so that the debugger can continue to run without
 | 
					        # root nursery so that the debugger can continue to run without
 | 
				
			||||||
| 
						 | 
					@ -328,13 +340,13 @@ async def _breakpoint(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # the lock must be released on pdb completion
 | 
					        # the lock must be released on pdb completion
 | 
				
			||||||
        def teardown():
 | 
					        def teardown():
 | 
				
			||||||
            global _pdb_complete, _debug_lock
 | 
					            global _local_pdb_complete, _debug_lock
 | 
				
			||||||
            global _global_actor_in_debug, _local_task_in_debug
 | 
					            global _global_actor_in_debug, _local_task_in_debug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _debug_lock.release()
 | 
					            _debug_lock.release()
 | 
				
			||||||
            _global_actor_in_debug = None
 | 
					            _global_actor_in_debug = None
 | 
				
			||||||
            _local_task_in_debug = None
 | 
					            _local_task_in_debug = None
 | 
				
			||||||
            _pdb_complete.set()
 | 
					            _local_pdb_complete.set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _pdb_release_hook = teardown
 | 
					        _pdb_release_hook = teardown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue