0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 00:56:44 +01:00
mongodb/buildscripts/resmokelib/sighandler.py
2019-04-08 14:08:49 -04:00

108 lines
3.7 KiB
Python

"""Utility to support asynchronously signaling the current process."""
import atexit
import os
import signal
import sys
import threading
import time
import traceback
_IS_WINDOWS = (sys.platform == "win32")
if _IS_WINDOWS:
import win32api
import win32event
from . import reportfile # pylint: disable=wrong-import-position
from . import testing # pylint: disable=wrong-import-position
def register(logger, suites, start_time):
"""Register an event object to wait for signal, or a signal handler for SIGUSR1."""
def _handle_sigusr1(signum, frame): # pylint: disable=unused-argument
"""Signal handler for SIGUSR1.
The handler will dump the stacks of all threads and write out the report file and
log suite summaries.
"""
header_msg = "Dumping stacks due to SIGUSR1 signal"
_dump_and_log(header_msg)
def _handle_set_event(event_handle):
"""Event object handler for Windows.
The handler will dump the stacks of all threads and write out the report file and
log suite summaries.
"""
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_and_log(header_msg)
def _dump_and_log(header_msg):
"""Dump the stacks of all threads, write report file, and log suite summaries."""
_dump_stacks(logger, header_msg)
reportfile.write(suites)
testing.suite.Suite.log_summaries(logger, suites, time.time() - start_time)
# 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() # pylint: disable=protected-access
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))