1# -*- coding:utf-8 -*-
2# Copyright 2016 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16"""Signal related functionality."""
17
18from __future__ import print_function
19
20import os
21import signal
22import sys
23
24_path = os.path.realpath(__file__ + '/../..')
25if sys.path[0] != _path:
26    sys.path.insert(0, _path)
27del _path
28
29
30def relay_signal(handler, signum, frame):
31    """Notify a listener returned from getsignal of receipt of a signal.
32
33    Returns:
34      True if it was relayed to the target, False otherwise.
35      False in particular occurs if the target isn't relayable.
36    """
37    if handler in (None, signal.SIG_IGN):
38        return True
39    elif handler == signal.SIG_DFL:
40        # This scenario is a fairly painful to handle fully, thus we just
41        # state we couldn't handle it and leave it to client code.
42        return False
43    handler(signum, frame)
44    return True
45
46
47def signal_module_usable(_signal=signal.signal, _SIGUSR1=signal.SIGUSR1):
48    """Verify that the signal module is usable and won't segfault on us.
49
50    See http://bugs.python.org/issue14173.  This function detects if the
51    signals module is no longer safe to use (which only occurs during
52    final stages of the interpreter shutdown) and heads off a segfault
53    if signal.* was accessed.
54
55    This shouldn't be used by anything other than functionality that is
56    known and unavoidably invoked by finalizer code during python shutdown.
57
58    Finally, the default args here are intentionally binding what we need
59    from the signal module to do the necessary test; invoking code shouldn't
60    pass any options, nor should any developer ever remove those default
61    options.
62
63    Note that this functionality is intended to be removed just as soon
64    as all consuming code installs their own SIGTERM handlers.
65    """
66    # Track any signals we receive while doing the check.
67    received, actual = [], None
68    def handler(signum, frame):
69        received.append([signum, frame])
70    try:
71        # Play with sigusr1, since it's not particularly used.
72        actual = _signal(_SIGUSR1, handler)
73        _signal(_SIGUSR1, actual)
74        return True
75    except (TypeError, AttributeError, SystemError, ValueError):
76        # The first three exceptions can be thrown depending on the state of the
77        # signal module internal Handlers array; we catch all, and interpret it
78        # as if we were invoked during sys.exit cleanup.
79        # The last exception can be thrown if we're trying to be used in a
80        # thread which is not the main one.  This can come up with standard
81        # python modules such as BaseHTTPServer.HTTPServer.
82        return False
83    finally:
84        # And now relay those signals to the original handler.  Not all may
85        # be delivered- the first may throw an exception for example.  Not our
86        # problem however.
87        for signum, frame in received:
88            actual(signum, frame)
89