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