bpo-43843: libregrtest uses threading.excepthook (GH-25400)

test.libregrtest now marks a test as ENV_CHANGED (altered the
execution environment) if a thread raises an exception but does not
catch it. It sets a hook on threading.excepthook. Use
--fail-env-changed option to mark the test as failed.

libregrtest regrtest_unraisable_hook() explicitly flushs
sys.stdout, sys.stderr and sys.__stderr__.
diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py
index 13efdb4..89d7e7e 100644
--- a/Lib/test/libregrtest/utils.py
+++ b/Lib/test/libregrtest/utils.py
@@ -68,14 +68,23 @@ def print_warning(msg):
 orig_unraisablehook = None
 
 
+def flush_std_streams():
+    if sys.stdout is not None:
+        sys.stdout.flush()
+    if sys.stderr is not None:
+        sys.stderr.flush()
+
+
 def regrtest_unraisable_hook(unraisable):
     global orig_unraisablehook
     support.environment_altered = True
     print_warning("Unraisable exception")
     old_stderr = sys.stderr
     try:
+        flush_std_streams()
         sys.stderr = sys.__stderr__
         orig_unraisablehook(unraisable)
+        sys.stderr.flush()
     finally:
         sys.stderr = old_stderr
 
@@ -86,6 +95,30 @@ def setup_unraisable_hook():
     sys.unraisablehook = regrtest_unraisable_hook
 
 
+orig_threading_excepthook = None
+
+
+def regrtest_threading_excepthook(args):
+    global orig_threading_excepthook
+    support.environment_altered = True
+    print_warning(f"Uncaught thread exception: {args.exc_type.__name__}")
+    old_stderr = sys.stderr
+    try:
+        flush_std_streams()
+        sys.stderr = sys.__stderr__
+        orig_threading_excepthook(args)
+        sys.stderr.flush()
+    finally:
+        sys.stderr = old_stderr
+
+
+def setup_threading_excepthook():
+    global orig_threading_excepthook
+    import threading
+    orig_threading_excepthook = threading.excepthook
+    threading.excepthook = regrtest_threading_excepthook
+
+
 def clear_caches():
     # Clear the warnings registry, so they can be displayed again
     for mod in sys.modules.values():