1 |
Fix portage commands to exit immediately for any unhandled |
2 |
exceptions that are raised while the asyncio event loop is running |
3 |
without a tty. If we have a tty then start the debugger, |
4 |
since in might aid in diagnosis of the problem. |
5 |
|
6 |
In order to avoid potential interference with API consumers, do not |
7 |
call set_exception_handler unless portage._internal_caller is True. |
8 |
|
9 |
Bug: https://bugs.gentoo.org/658684 |
10 |
--- |
11 |
pym/portage/util/_eventloop/asyncio_event_loop.py | 31 +++++++++++++++++++++++ |
12 |
1 file changed, 31 insertions(+) |
13 |
|
14 |
diff --git a/pym/portage/util/_eventloop/asyncio_event_loop.py b/pym/portage/util/_eventloop/asyncio_event_loop.py |
15 |
index c07b71103c..ea0e03b23b 100644 |
16 |
--- a/pym/portage/util/_eventloop/asyncio_event_loop.py |
17 |
+++ b/pym/portage/util/_eventloop/asyncio_event_loop.py |
18 |
@@ -2,7 +2,9 @@ |
19 |
# Distributed under the terms of the GNU General Public License v2 |
20 |
|
21 |
import os |
22 |
+import pdb |
23 |
import signal |
24 |
+import sys |
25 |
|
26 |
try: |
27 |
import asyncio as _real_asyncio |
28 |
@@ -53,6 +55,35 @@ class AsyncioEventLoop(_AbstractEventLoop): |
29 |
self.get_debug = loop.get_debug |
30 |
self._wakeup_fd = -1 |
31 |
|
32 |
+ if portage._internal_caller: |
33 |
+ loop.set_exception_handler(self._internal_caller_exception_handler) |
34 |
+ |
35 |
+ @staticmethod |
36 |
+ def _internal_caller_exception_handler(loop, context): |
37 |
+ """ |
38 |
+ An exception handler which drops to a pdb shell if std* streams |
39 |
+ refer to a tty, and otherwise kills the process with SIGTERM. |
40 |
+ |
41 |
+ In order to avoid potential interference with API consumers, this |
42 |
+ implementation is only used when portage._internal_caller is True. |
43 |
+ """ |
44 |
+ loop.default_exception_handler(context) |
45 |
+ if 'exception' in context: |
46 |
+ # If we have a tty then start the debugger, since in might |
47 |
+ # aid in diagnosis of the problem. If there's no tty, then |
48 |
+ # exit immediately. |
49 |
+ if all(s.isatty() for s in (sys.stdout, sys.stderr, sys.stdin)): |
50 |
+ pdb.set_trace() |
51 |
+ else: |
52 |
+ # Normally emerge will wait for all coroutines to complete |
53 |
+ # after SIGTERM has been received. However, an unhandled |
54 |
+ # exception will prevent the interrupted coroutine from |
55 |
+ # completing, therefore use the default SIGTERM handler |
56 |
+ # in order to ensure that emerge exits immediately (though |
57 |
+ # uncleanly). |
58 |
+ signal.signal(signal.SIGTERM, signal.SIG_DFL) |
59 |
+ os.kill(os.getpid(), signal.SIGTERM) |
60 |
+ |
61 |
def _create_future(self): |
62 |
""" |
63 |
Provide AbstractEventLoop.create_future() for python3.4. |
64 |
-- |
65 |
2.13.6 |