mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
111 lines
3.5 KiB
Python
111 lines
3.5 KiB
Python
"""
|
|
Utility to support asynchronously signaling the current process.
|
|
"""
|
|
|
|
from __future__ import absolute_import
|
|
|
|
import atexit
|
|
import os
|
|
import signal
|
|
import sys
|
|
import threading
|
|
import traceback
|
|
|
|
_is_windows = (sys.platform == "win32")
|
|
if _is_windows:
|
|
import win32api
|
|
import win32event
|
|
|
|
from . import reportfile
|
|
|
|
|
|
def register(logger, suites):
|
|
"""
|
|
On Windows, set up an event object to wait for signal, otherwise, register a signal handler
|
|
for the SIGUSR1 signal.
|
|
"""
|
|
|
|
def _handle_sigusr1(signum, frame):
|
|
"""
|
|
Signal handler that will dump the stacks of all threads and
|
|
then write out the report file.
|
|
"""
|
|
|
|
header_msg = "Dumping stacks due to SIGUSR1 signal"
|
|
|
|
_dump_stacks(logger, header_msg)
|
|
reportfile.write(suites)
|
|
|
|
def _handle_set_event(event_handle):
|
|
"""
|
|
Windows event object handler that will dump the stacks of all threads and then write out
|
|
the report file.
|
|
"""
|
|
|
|
while True:
|
|
try:
|
|
# Wait for task time out to dump stacks.
|
|
ret = win32event.WaitForSingleObject(event_handle, win32event.INFINITE)
|
|
if ret != win32event.WAIT_OBJECT_0:
|
|
logger.error("_handle_set_event WaitForSingleObject failed: %d" % ret)
|
|
return
|
|
except win32event.error as err:
|
|
logger.error("Exception from win32event.WaitForSingleObject with error: %s" % err)
|
|
else:
|
|
header_msg = "Dumping stacks due to signal from win32event.SetEvent"
|
|
|
|
_dump_stacks(logger, header_msg)
|
|
reportfile.write(suites)
|
|
|
|
|
|
# On Windows spawn a thread to wait on an event object for signal to dump stacks. For Cygwin
|
|
# platforms, we use a signal handler since it supports POSIX signals.
|
|
if _is_windows:
|
|
# Create unique event_name.
|
|
event_name = "Global\\Mongo_Python_" + str(os.getpid())
|
|
|
|
try:
|
|
security_attributes = None
|
|
manual_reset = False
|
|
initial_state = False
|
|
task_timeout_handle = win32event.CreateEvent(security_attributes,
|
|
manual_reset,
|
|
initial_state,
|
|
event_name)
|
|
except win32event.error as err:
|
|
logger.error("Exception from win32event.CreateEvent with error: %s" % err)
|
|
return
|
|
|
|
# Register to close event object handle on exit.
|
|
atexit.register(win32api.CloseHandle, task_timeout_handle)
|
|
|
|
# Create thread.
|
|
event_handler_thread = threading.Thread(target=_handle_set_event,
|
|
kwargs={"event_handle": task_timeout_handle},
|
|
name="windows_event_handler_thread")
|
|
event_handler_thread.daemon = True
|
|
event_handler_thread.start()
|
|
else:
|
|
# Otherwise register a signal handler
|
|
signal.signal(signal.SIGUSR1, _handle_sigusr1)
|
|
|
|
|
|
def _dump_stacks(logger, header_msg):
|
|
"""
|
|
Signal handler that will dump the stacks of all threads.
|
|
"""
|
|
|
|
sb = []
|
|
sb.append(header_msg)
|
|
|
|
frames = sys._current_frames()
|
|
sb.append("Total threads: %d" % (len(frames)))
|
|
sb.append("")
|
|
|
|
for thread_id in frames:
|
|
stack = frames[thread_id]
|
|
sb.append("Thread %d:" % (thread_id))
|
|
sb.append("".join(traceback.format_stack(stack)))
|
|
|
|
logger.info("\n".join(sb))
|