OLD | NEW |
| (Empty) |
1 # -*- coding: utf-8 -*- | |
2 # Copyright 2015 Google Inc. All Rights Reserved. | |
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 """Signal handling functions.""" | |
16 | |
17 from __future__ import absolute_import | |
18 | |
19 import signal | |
20 from gslib.util import IS_WINDOWS | |
21 | |
22 | |
23 # Maps from signal_num to list of signal handlers to call. | |
24 _non_final_signal_handlers = {} | |
25 # Maps from signal_num to the final signal handler (if any) that should be | |
26 # called for that signal. | |
27 _final_signal_handlers = {} | |
28 | |
29 | |
30 def RegisterSignalHandler(signal_num, handler, is_final_handler=False): | |
31 """Registers a handler for signal signal_num. | |
32 | |
33 Unlike calling signal.signal(): | |
34 - This function can be called from any thread (and will cause the handler to | |
35 be run by the main thread when the signal is received). | |
36 - Handlers are cumulative: When a given signal is received, all registered | |
37 handlers will be executed (with the exception that only the last handler | |
38 to register with is_final_handler=True will be called). | |
39 | |
40 Handlers should make no ordering assumptions, other than that the last handler | |
41 to register with is_final_handler=True will be called after all the other | |
42 handlers. | |
43 | |
44 Args: | |
45 signal_num: The signal number with which to associate handler. | |
46 handler: The handler. | |
47 is_final_handler: Bool indicator whether handler should be called last among | |
48 all the handlers for this signal_num. The last handler to | |
49 register this way survives; other handlers registered with | |
50 is_final_handler=True will not be called when the signal | |
51 is received. | |
52 Raises: | |
53 RuntimeError: if attempt is made to register a signal_num not in | |
54 GetCaughtSignals. | |
55 """ | |
56 if signal_num not in GetCaughtSignals(): | |
57 raise RuntimeError('Attempt to register handler (%s) for signal %d, which ' | |
58 'is not in GetCaughtSignals' % (handler, signal_num)) | |
59 if is_final_handler: | |
60 _final_signal_handlers[signal_num] = handler | |
61 else: | |
62 _non_final_signal_handlers[signal_num].append(handler) | |
63 | |
64 | |
65 def _SignalHandler(signal_num, cur_stack_frame): | |
66 """Global signal handler. | |
67 | |
68 When a signal is caught we execute each registered handler for that signal. | |
69 | |
70 Args: | |
71 signal_num: Signal that was caught. | |
72 cur_stack_frame: Unused. | |
73 """ | |
74 if signal_num in _non_final_signal_handlers: | |
75 for handler in _non_final_signal_handlers[signal_num]: | |
76 handler(signal_num, cur_stack_frame) | |
77 if signal_num in _final_signal_handlers: | |
78 _final_signal_handlers[signal_num](signal_num, cur_stack_frame) | |
79 | |
80 | |
81 def InitializeSignalHandling(): | |
82 """Initializes global signal handling. | |
83 | |
84 Sets up global signal handler for each signal we handle. | |
85 """ | |
86 for signal_num in GetCaughtSignals(): | |
87 _non_final_signal_handlers[signal_num] = [] | |
88 # Make main signal handler catch the signal. | |
89 signal.signal(signal_num, _SignalHandler) | |
90 | |
91 | |
92 def GetCaughtSignals(): | |
93 """Returns terminating signals that can be caught on this OS platform.""" | |
94 signals = [signal.SIGINT, signal.SIGTERM] | |
95 if not IS_WINDOWS: | |
96 # Windows doesn't have SIGQUIT. | |
97 signals.append(signal.SIGQUIT) | |
98 return signals | |
99 | |
OLD | NEW |