# Copyright (c) Microsoft Corporation. All rights reserved. | |
# Licensed under the MIT License. See LICENSE in the project root | |
# for license information. | |
"""Provides facilities to dump all stacks of all threads in the process. | |
""" | |
import os | |
import sys | |
import time | |
import threading | |
import traceback | |
from debugpy.common import log | |
def dump(): | |
"""Dump stacks of all threads in this process, except for the current thread.""" | |
tid = threading.current_thread().ident | |
pid = os.getpid() | |
log.info("Dumping stacks for process {0}...", pid) | |
for t_ident, frame in sys._current_frames().items(): | |
if t_ident == tid: | |
continue | |
for t in threading.enumerate(): | |
if t.ident == tid: | |
t_name = t.name | |
t_daemon = t.daemon | |
break | |
else: | |
t_name = t_daemon = "<unknown>" | |
stack = "".join(traceback.format_stack(frame)) | |
log.info( | |
"Stack of thread {0} (tid={1}, pid={2}, daemon={3}):\n\n{4}", | |
t_name, | |
t_ident, | |
pid, | |
t_daemon, | |
stack, | |
) | |
log.info("Finished dumping stacks for process {0}.", pid) | |
def dump_after(secs): | |
"""Invokes dump() on a background thread after waiting for the specified time.""" | |
def dumper(): | |
time.sleep(secs) | |
try: | |
dump() | |
except: | |
log.swallow_exception() | |
thread = threading.Thread(target=dumper) | |
thread.daemon = True | |
thread.start() | |