Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH] AsyncioEventLoop: exit after unhandled exception (bug 658684)
Date: Fri, 22 Jun 2018 15:52:10
Message-Id: 20180622155145.20815-1-zmedico@gentoo.org
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