Implement initial Python bindings for Open vSwitch database.
[sliver-openvswitch.git] / python / ovs / fatal_signal.py
1 # Copyright (c) 2010 Nicira Networks
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import atexit
16 import logging
17 import os
18 import signal
19
20 _inited = False
21 _hooks = []
22
23 def _init():
24     global _inited
25     if not _inited:
26         _inited = True
27
28         for signr in (signal.SIGTERM, signal.SIGINT,
29                       signal.SIGHUP, signal.SIGALRM):
30             if signal.getsignal(signr) == signal.SIG_DFL:
31                 signal.signal(signr, _signal_handler)
32         atexit.register(_atexit_handler)
33
34 def add_hook(hook, cancel, run_at_exit):
35     _init()
36
37     global _hooks
38     _hooks.append((hook, cancel, run_at_exit))
39
40 def fork():
41     """Clears all of the fatal signal hooks without executing them.  If any of
42     the hooks passed a 'cancel' function to add_hook(), then those functions
43     will be called, allowing them to free resources, etc.
44
45     Following a fork, one of the resulting processes can call this function to
46     allow it to terminate without calling the hooks registered before calling
47     this function.  New hooks registered after calling this function will take
48     effect normally."""
49     global _hooks
50     for hook, cancel, run_at_exit in _hooks:
51         if cancel:
52             cancel()
53
54     _hooks = []
55 \f
56 _added_hook = False
57 _files = {}
58
59 def add_file_to_unlink(file):
60     """Registers 'file' to be unlinked when the program terminates via
61     sys.exit() or a fatal signal."""
62     global _added_hook
63     if not _added_hook:
64         _added_hook = True
65         add_hook(_unlink_files, _cancel_files, True)
66     _files[file] = None
67
68 def remove_file_to_unlink(file):
69     """Unregisters 'file' from being unlinked when the program terminates via
70     sys.exit() or a fatal signal."""
71     if file in _files:
72         del _files[file]
73
74 def unlink_file_now(file):
75     """Like fatal_signal_remove_file_to_unlink(), but also unlinks 'file'.
76     Returns 0 if successful, otherwise a positive errno value."""
77     error = _unlink(file)
78     if error:
79         logging.warning("could not unlink \"%s\" (%s)"
80                         % (file, os.strerror(error)))
81     remove_file_to_unlink(file)
82     return error
83
84 def _unlink_files():
85     for file in _files:
86         _unlink(file)
87
88 def _cancel_files():
89     global _added_hook
90     global _files
91     _added_hook = False
92     _files = {}
93
94 def _unlink(file):
95     try:
96         os.unlink(file)
97         return 0
98     except OSError, e:
99         return e.errno
100 \f
101 def _signal_handler(signr, frame):
102     _call_hooks(signr)
103
104     # Re-raise the signal with the default handling so that the program
105     # termination status reflects that we were killed by this signal.
106     signal.signal(signr, signal.SIG_DFL)
107     os.kill(os.getpid(), signr)
108
109 def _atexit_handler():
110     _call_hooks(0)
111
112 recurse = False
113 def _call_hooks(signr):
114     global recurse
115     if recurse:
116         return
117     recurse = True
118
119     for hook, cancel, run_at_exit in _hooks:
120         if signr != 0 or run_at_exit:
121             hook()