blob: 8c12b213d00024ad6e0cc5abbf3b7360bfc1b4ad [file] [log] [blame]
Victor Stinner024e37a2011-03-31 01:31:06 +02001from contextlib import contextmanager
Victor Stinnerc790a532011-04-08 13:39:59 +02002import datetime
Victor Stinner024e37a2011-03-31 01:31:06 +02003import faulthandler
Victor Stinner7e32f3a2011-06-29 13:44:05 +02004import os
Victor Stinner024e37a2011-03-31 01:31:06 +02005import re
6import signal
7import subprocess
8import sys
9from test import support, script_helper
Victor Stinnerd5698cb2012-07-31 02:55:49 +020010from test.script_helper import assert_python_ok
Victor Stinner024e37a2011-03-31 01:31:06 +020011import tempfile
12import unittest
13
Victor Stinnerff4cd882011-04-07 11:50:25 +020014try:
15 import threading
16 HAVE_THREADS = True
17except ImportError:
18 HAVE_THREADS = False
19
Victor Stinner44378d42011-04-01 15:37:12 +020020TIMEOUT = 0.5
21
Victor Stinner024e37a2011-03-31 01:31:06 +020022try:
23 from resource import setrlimit, RLIMIT_CORE, error as resource_error
24except ImportError:
25 prepare_subprocess = None
26else:
27 def prepare_subprocess():
28 # don't create core file
29 try:
30 setrlimit(RLIMIT_CORE, (0, 0))
31 except (ValueError, resource_error):
32 pass
33
Victor Stinner301f3f02011-06-01 13:49:12 +020034def expected_traceback(lineno1, lineno2, header, min_count=1):
Victor Stinner024e37a2011-03-31 01:31:06 +020035 regex = header
Victor Stinner7ad24e92011-03-31 22:35:49 +020036 regex += ' File "<string>", line %s in func\n' % lineno1
37 regex += ' File "<string>", line %s in <module>' % lineno2
Victor Stinner301f3f02011-06-01 13:49:12 +020038 if 1 < min_count:
39 return '^' + (regex + '\n') * (min_count - 1) + regex
40 else:
41 return '^' + regex + '$'
Victor Stinner024e37a2011-03-31 01:31:06 +020042
43@contextmanager
44def temporary_filename():
45 filename = tempfile.mktemp()
46 try:
47 yield filename
48 finally:
49 support.unlink(filename)
50
51class FaultHandlerTests(unittest.TestCase):
Victor Stinner05585cb2011-03-31 13:29:56 +020052 def get_output(self, code, filename=None):
Victor Stinner024e37a2011-03-31 01:31:06 +020053 """
54 Run the specified code in Python (in a new child process) and read the
55 output from the standard error or from a file (if filename is set).
56 Return the output lines as a list.
57
58 Strip the reference count from the standard error for Python debug
59 build, and replace "Current thread 0x00007f8d8fbd9700" by "Current
60 thread XXX".
61 """
62 options = {}
63 if prepare_subprocess:
64 options['preexec_fn'] = prepare_subprocess
65 process = script_helper.spawn_python('-c', code, **options)
66 stdout, stderr = process.communicate()
67 exitcode = process.wait()
Victor Stinner19402332011-03-31 18:15:52 +020068 output = support.strip_python_stderr(stdout)
69 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020070 if filename:
Victor Stinner19402332011-03-31 18:15:52 +020071 self.assertEqual(output, '')
Victor Stinner024e37a2011-03-31 01:31:06 +020072 with open(filename, "rb") as fp:
73 output = fp.read()
Victor Stinner19402332011-03-31 18:15:52 +020074 output = output.decode('ascii', 'backslashreplace')
Victor Stinner024e37a2011-03-31 01:31:06 +020075 output = re.sub('Current thread 0x[0-9a-f]+',
76 'Current thread XXX',
77 output)
Victor Stinner05585cb2011-03-31 13:29:56 +020078 return output.splitlines(), exitcode
Victor Stinner024e37a2011-03-31 01:31:06 +020079
80 def check_fatal_error(self, code, line_number, name_regex,
Victor Stinner7bba62f2011-05-07 12:43:00 +020081 filename=None, all_threads=True, other_regex=None):
Victor Stinner024e37a2011-03-31 01:31:06 +020082 """
83 Check that the fault handler for fatal errors is enabled and check the
84 traceback from the child process output.
85
86 Raise an error if the output doesn't match the expected format.
87 """
88 if all_threads:
89 header = 'Current thread XXX'
90 else:
91 header = 'Traceback (most recent call first)'
92 regex = """
93^Fatal Python error: {name}
94
95{header}:
Vinay Sajip36371232012-05-06 11:28:46 +010096 File "<string>", line {lineno} in <module>
Victor Stinner024e37a2011-03-31 01:31:06 +020097""".strip()
98 regex = regex.format(
99 lineno=line_number,
100 name=name_regex,
101 header=re.escape(header))
Victor Stinnerf0480752011-03-31 11:34:08 +0200102 if other_regex:
103 regex += '|' + other_regex
Victor Stinner05585cb2011-03-31 13:29:56 +0200104 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200105 output = '\n'.join(output)
106 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200107 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200108
109 def test_read_null(self):
110 self.check_fatal_error("""
111import faulthandler
112faulthandler.enable()
113faulthandler._read_null()
114""".strip(),
115 3,
Victor Stinnera8db3782011-08-08 22:43:45 +0200116 # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
117 '(?:Segmentation fault|Bus error|Illegal instruction)')
Victor Stinner024e37a2011-03-31 01:31:06 +0200118
119 def test_sigsegv(self):
120 self.check_fatal_error("""
121import faulthandler
122faulthandler.enable()
123faulthandler._sigsegv()
124""".strip(),
125 3,
126 'Segmentation fault')
127
Victor Stinnerd727e232011-04-01 12:13:55 +0200128 def test_sigabrt(self):
129 self.check_fatal_error("""
130import faulthandler
131faulthandler.enable()
132faulthandler._sigabrt()
133""".strip(),
134 3,
135 'Aborted')
136
Victor Stinner024e37a2011-03-31 01:31:06 +0200137 @unittest.skipIf(sys.platform == 'win32',
138 "SIGFPE cannot be caught on Windows")
139 def test_sigfpe(self):
140 self.check_fatal_error("""
141import faulthandler
142faulthandler.enable()
143faulthandler._sigfpe()
144""".strip(),
145 3,
146 'Floating point exception')
147
148 @unittest.skipIf(not hasattr(faulthandler, '_sigbus'),
149 "need faulthandler._sigbus()")
150 def test_sigbus(self):
151 self.check_fatal_error("""
152import faulthandler
153faulthandler.enable()
154faulthandler._sigbus()
155""".strip(),
156 3,
157 'Bus error')
158
159 @unittest.skipIf(not hasattr(faulthandler, '_sigill'),
160 "need faulthandler._sigill()")
161 def test_sigill(self):
162 self.check_fatal_error("""
163import faulthandler
164faulthandler.enable()
165faulthandler._sigill()
166""".strip(),
167 3,
168 'Illegal instruction')
169
170 def test_fatal_error(self):
171 self.check_fatal_error("""
172import faulthandler
173faulthandler._fatal_error(b'xyz')
174""".strip(),
175 2,
176 'xyz')
177
Charles-François Natali3391e642011-09-01 23:08:21 +0200178 @unittest.skipIf(sys.platform.startswith('openbsd') and HAVE_THREADS,
179 "Issue #12868: sigaltstack() doesn't work on "
180 "OpenBSD if Python is compiled with pthread")
Victor Stinner024e37a2011-03-31 01:31:06 +0200181 @unittest.skipIf(not hasattr(faulthandler, '_stack_overflow'),
182 'need faulthandler._stack_overflow()')
183 def test_stack_overflow(self):
184 self.check_fatal_error("""
185import faulthandler
186faulthandler.enable()
187faulthandler._stack_overflow()
188""".strip(),
189 3,
Victor Stinnerf0480752011-03-31 11:34:08 +0200190 '(?:Segmentation fault|Bus error)',
191 other_regex='unable to raise a stack overflow')
Victor Stinner024e37a2011-03-31 01:31:06 +0200192
193 def test_gil_released(self):
194 self.check_fatal_error("""
195import faulthandler
196faulthandler.enable()
197faulthandler._read_null(True)
198""".strip(),
199 3,
Victor Stinnera8db3782011-08-08 22:43:45 +0200200 '(?:Segmentation fault|Bus error|Illegal instruction)')
Victor Stinner024e37a2011-03-31 01:31:06 +0200201
202 def test_enable_file(self):
203 with temporary_filename() as filename:
204 self.check_fatal_error("""
205import faulthandler
206output = open({filename}, 'wb')
207faulthandler.enable(output)
Victor Stinner44378d42011-04-01 15:37:12 +0200208faulthandler._read_null()
Victor Stinner024e37a2011-03-31 01:31:06 +0200209""".strip().format(filename=repr(filename)),
210 4,
Victor Stinnera8db3782011-08-08 22:43:45 +0200211 '(?:Segmentation fault|Bus error|Illegal instruction)',
Victor Stinner024e37a2011-03-31 01:31:06 +0200212 filename=filename)
213
Victor Stinner7bba62f2011-05-07 12:43:00 +0200214 def test_enable_single_thread(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200215 self.check_fatal_error("""
216import faulthandler
Victor Stinner7bba62f2011-05-07 12:43:00 +0200217faulthandler.enable(all_threads=False)
Victor Stinner44378d42011-04-01 15:37:12 +0200218faulthandler._read_null()
Victor Stinner024e37a2011-03-31 01:31:06 +0200219""".strip(),
220 3,
Victor Stinnera8db3782011-08-08 22:43:45 +0200221 '(?:Segmentation fault|Bus error|Illegal instruction)',
Victor Stinner7bba62f2011-05-07 12:43:00 +0200222 all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200223
224 def test_disable(self):
225 code = """
226import faulthandler
227faulthandler.enable()
228faulthandler.disable()
229faulthandler._read_null()
230""".strip()
231 not_expected = 'Fatal Python error'
Victor Stinner05585cb2011-03-31 13:29:56 +0200232 stderr, exitcode = self.get_output(code)
Victor Stinner024e37a2011-03-31 01:31:06 +0200233 stder = '\n'.join(stderr)
234 self.assertTrue(not_expected not in stderr,
235 "%r is present in %r" % (not_expected, stderr))
Victor Stinner05585cb2011-03-31 13:29:56 +0200236 self.assertNotEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200237
238 def test_is_enabled(self):
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200239 orig_stderr = sys.stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200240 try:
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200241 # regrtest may replace sys.stderr by io.StringIO object, but
242 # faulthandler.enable() requires that sys.stderr has a fileno()
243 # method
Victor Stinner72488502011-06-29 23:24:31 +0200244 sys.stderr = sys.__stderr__
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200245
246 was_enabled = faulthandler.is_enabled()
247 try:
Victor Stinner024e37a2011-03-31 01:31:06 +0200248 faulthandler.enable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200249 self.assertTrue(faulthandler.is_enabled())
Victor Stinner024e37a2011-03-31 01:31:06 +0200250 faulthandler.disable()
Victor Stinner7e32f3a2011-06-29 13:44:05 +0200251 self.assertFalse(faulthandler.is_enabled())
252 finally:
253 if was_enabled:
254 faulthandler.enable()
255 else:
256 faulthandler.disable()
257 finally:
258 sys.stderr = orig_stderr
Victor Stinner024e37a2011-03-31 01:31:06 +0200259
Victor Stinnerd5698cb2012-07-31 02:55:49 +0200260 def test_disabled_by_default(self):
261 # By default, the module should be disabled
262 code = "import faulthandler; print(faulthandler.is_enabled())"
263 rc, stdout, stderr = assert_python_ok("-c", code)
264 stdout = (stdout + stderr).strip()
265 self.assertEqual(stdout, b"False")
266
267 def test_sys_xoptions(self):
268 # Test python -X faulthandler
269 code = "import faulthandler; print(faulthandler.is_enabled())"
270 rc, stdout, stderr = assert_python_ok("-X", "faulthandler", "-c", code)
271 stdout = (stdout + stderr).strip()
272 self.assertEqual(stdout, b"True")
273
Victor Stinner024e37a2011-03-31 01:31:06 +0200274 def check_dump_traceback(self, filename):
275 """
276 Explicitly call dump_traceback() function and check its output.
277 Raise an error if the output doesn't match the expected format.
278 """
279 code = """
280import faulthandler
281
282def funcB():
283 if {has_filename}:
284 with open({filename}, "wb") as fp:
Victor Stinner7bba62f2011-05-07 12:43:00 +0200285 faulthandler.dump_traceback(fp, all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200286 else:
Victor Stinner7bba62f2011-05-07 12:43:00 +0200287 faulthandler.dump_traceback(all_threads=False)
Victor Stinner024e37a2011-03-31 01:31:06 +0200288
289def funcA():
290 funcB()
291
292funcA()
293""".strip()
294 code = code.format(
295 filename=repr(filename),
296 has_filename=bool(filename),
297 )
298 if filename:
299 lineno = 6
300 else:
301 lineno = 8
302 expected = [
303 'Traceback (most recent call first):',
304 ' File "<string>", line %s in funcB' % lineno,
305 ' File "<string>", line 11 in funcA',
306 ' File "<string>", line 13 in <module>'
307 ]
Victor Stinner05585cb2011-03-31 13:29:56 +0200308 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200309 self.assertEqual(trace, expected)
Victor Stinner05585cb2011-03-31 13:29:56 +0200310 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200311
312 def test_dump_traceback(self):
313 self.check_dump_traceback(None)
Victor Stinner19402332011-03-31 18:15:52 +0200314
315 def test_dump_traceback_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200316 with temporary_filename() as filename:
317 self.check_dump_traceback(filename)
318
Victor Stinnerff4cd882011-04-07 11:50:25 +0200319 @unittest.skipIf(not HAVE_THREADS, 'need threads')
Victor Stinner024e37a2011-03-31 01:31:06 +0200320 def check_dump_traceback_threads(self, filename):
321 """
322 Call explicitly dump_traceback(all_threads=True) and check the output.
323 Raise an error if the output doesn't match the expected format.
324 """
325 code = """
326import faulthandler
327from threading import Thread, Event
328import time
329
330def dump():
331 if {filename}:
332 with open({filename}, "wb") as fp:
333 faulthandler.dump_traceback(fp, all_threads=True)
334 else:
335 faulthandler.dump_traceback(all_threads=True)
336
337class Waiter(Thread):
338 # avoid blocking if the main thread raises an exception.
339 daemon = True
340
341 def __init__(self):
342 Thread.__init__(self)
343 self.running = Event()
344 self.stop = Event()
345
346 def run(self):
347 self.running.set()
348 self.stop.wait()
349
350waiter = Waiter()
351waiter.start()
352waiter.running.wait()
353dump()
354waiter.stop.set()
355waiter.join()
356""".strip()
357 code = code.format(filename=repr(filename))
Victor Stinner05585cb2011-03-31 13:29:56 +0200358 output, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200359 output = '\n'.join(output)
360 if filename:
361 lineno = 8
362 else:
363 lineno = 10
364 regex = """
365^Thread 0x[0-9a-f]+:
Victor Stinner1b3241f2011-04-03 18:41:22 +0200366(?: File ".*threading.py", line [0-9]+ in [_a-z]+
367){{1,3}} File "<string>", line 23 in run
Victor Stinner024e37a2011-03-31 01:31:06 +0200368 File ".*threading.py", line [0-9]+ in _bootstrap_inner
369 File ".*threading.py", line [0-9]+ in _bootstrap
370
371Current thread XXX:
372 File "<string>", line {lineno} in dump
373 File "<string>", line 28 in <module>$
374""".strip()
375 regex = regex.format(lineno=lineno)
376 self.assertRegex(output, regex)
Victor Stinner05585cb2011-03-31 13:29:56 +0200377 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200378
379 def test_dump_traceback_threads(self):
380 self.check_dump_traceback_threads(None)
Victor Stinner19402332011-03-31 18:15:52 +0200381
382 def test_dump_traceback_threads_file(self):
Victor Stinner024e37a2011-03-31 01:31:06 +0200383 with temporary_filename() as filename:
384 self.check_dump_traceback_threads(filename)
385
Victor Stinnerde10f402011-04-08 12:57:06 +0200386 def _check_dump_tracebacks_later(self, repeat, cancel, filename, loops):
Victor Stinner024e37a2011-03-31 01:31:06 +0200387 """
388 Check how many times the traceback is written in timeout x 2.5 seconds,
389 or timeout x 3.5 seconds if cancel is True: 1, 2 or 3 times depending
390 on repeat and cancel options.
391
392 Raise an error if the output doesn't match the expect format.
393 """
Victor Stinnerc790a532011-04-08 13:39:59 +0200394 timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
Victor Stinner024e37a2011-03-31 01:31:06 +0200395 code = """
396import faulthandler
397import time
398
Victor Stinnerde10f402011-04-08 12:57:06 +0200399def func(timeout, repeat, cancel, file, loops):
400 for loop in range(loops):
401 faulthandler.dump_tracebacks_later(timeout, repeat=repeat, file=file)
402 if cancel:
403 faulthandler.cancel_dump_tracebacks_later()
Victor Stinner301f3f02011-06-01 13:49:12 +0200404 time.sleep(timeout * 5)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200405 faulthandler.cancel_dump_tracebacks_later()
Victor Stinner024e37a2011-03-31 01:31:06 +0200406
Victor Stinner44378d42011-04-01 15:37:12 +0200407timeout = {timeout}
Victor Stinner024e37a2011-03-31 01:31:06 +0200408repeat = {repeat}
409cancel = {cancel}
Victor Stinnerde10f402011-04-08 12:57:06 +0200410loops = {loops}
Victor Stinner024e37a2011-03-31 01:31:06 +0200411if {has_filename}:
412 file = open({filename}, "wb")
413else:
414 file = None
Victor Stinnerde10f402011-04-08 12:57:06 +0200415func(timeout, repeat, cancel, file, loops)
Victor Stinner024e37a2011-03-31 01:31:06 +0200416if file is not None:
417 file.close()
418""".strip()
419 code = code.format(
Victor Stinnerde10f402011-04-08 12:57:06 +0200420 timeout=TIMEOUT,
Victor Stinner024e37a2011-03-31 01:31:06 +0200421 repeat=repeat,
422 cancel=cancel,
Victor Stinnerde10f402011-04-08 12:57:06 +0200423 loops=loops,
424 has_filename=bool(filename),
425 filename=repr(filename),
Victor Stinner024e37a2011-03-31 01:31:06 +0200426 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200427 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200428 trace = '\n'.join(trace)
429
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200430 if not cancel:
Victor Stinnerde10f402011-04-08 12:57:06 +0200431 count = loops
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200432 if repeat:
Victor Stinnerde10f402011-04-08 12:57:06 +0200433 count *= 2
Victor Stinnerc790a532011-04-08 13:39:59 +0200434 header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+:\n' % timeout_str
Victor Stinner301f3f02011-06-01 13:49:12 +0200435 regex = expected_traceback(9, 20, header, min_count=count)
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200436 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200437 else:
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200438 self.assertEqual(trace, '')
Victor Stinner05585cb2011-03-31 13:29:56 +0200439 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200440
441 @unittest.skipIf(not hasattr(faulthandler, 'dump_tracebacks_later'),
442 'need faulthandler.dump_tracebacks_later()')
443 def check_dump_tracebacks_later(self, repeat=False, cancel=False,
Victor Stinnerde10f402011-04-08 12:57:06 +0200444 file=False, twice=False):
445 if twice:
446 loops = 2
447 else:
448 loops = 1
Victor Stinner024e37a2011-03-31 01:31:06 +0200449 if file:
450 with temporary_filename() as filename:
Victor Stinnerde10f402011-04-08 12:57:06 +0200451 self._check_dump_tracebacks_later(repeat, cancel,
452 filename, loops)
Victor Stinner024e37a2011-03-31 01:31:06 +0200453 else:
Victor Stinnerde10f402011-04-08 12:57:06 +0200454 self._check_dump_tracebacks_later(repeat, cancel, None, loops)
Victor Stinner024e37a2011-03-31 01:31:06 +0200455
456 def test_dump_tracebacks_later(self):
457 self.check_dump_tracebacks_later()
458
459 def test_dump_tracebacks_later_repeat(self):
460 self.check_dump_tracebacks_later(repeat=True)
461
Victor Stinnerf77ccc62011-04-03 18:45:42 +0200462 def test_dump_tracebacks_later_cancel(self):
463 self.check_dump_tracebacks_later(cancel=True)
Victor Stinner024e37a2011-03-31 01:31:06 +0200464
465 def test_dump_tracebacks_later_file(self):
466 self.check_dump_tracebacks_later(file=True)
467
Victor Stinnerde10f402011-04-08 12:57:06 +0200468 def test_dump_tracebacks_later_twice(self):
469 self.check_dump_tracebacks_later(twice=True)
470
Victor Stinner024e37a2011-03-31 01:31:06 +0200471 @unittest.skipIf(not hasattr(faulthandler, "register"),
472 "need faulthandler.register")
Victor Stinnera01ca122011-04-01 12:56:17 +0200473 def check_register(self, filename=False, all_threads=False,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200474 unregister=False, chain=False):
Victor Stinner024e37a2011-03-31 01:31:06 +0200475 """
476 Register a handler displaying the traceback on a user signal. Raise the
477 signal and check the written traceback.
478
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200479 If chain is True, check that the previous signal handler is called.
480
Victor Stinner024e37a2011-03-31 01:31:06 +0200481 Raise an error if the output doesn't match the expected format.
482 """
Victor Stinnera01ca122011-04-01 12:56:17 +0200483 signum = signal.SIGUSR1
Victor Stinner024e37a2011-03-31 01:31:06 +0200484 code = """
485import faulthandler
486import os
487import signal
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200488import sys
Victor Stinner024e37a2011-03-31 01:31:06 +0200489
490def func(signum):
491 os.kill(os.getpid(), signum)
492
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200493def handler(signum, frame):
494 handler.called = True
495handler.called = False
496
497exitcode = 0
Victor Stinnera01ca122011-04-01 12:56:17 +0200498signum = {signum}
499unregister = {unregister}
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200500chain = {chain}
501
Victor Stinner024e37a2011-03-31 01:31:06 +0200502if {has_filename}:
503 file = open({filename}, "wb")
504else:
505 file = None
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200506if chain:
507 signal.signal(signum, handler)
508faulthandler.register(signum, file=file,
509 all_threads={all_threads}, chain={chain})
Victor Stinnera01ca122011-04-01 12:56:17 +0200510if unregister:
511 faulthandler.unregister(signum)
Victor Stinner024e37a2011-03-31 01:31:06 +0200512func(signum)
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200513if chain and not handler.called:
514 if file is not None:
515 output = file
516 else:
517 output = sys.stderr
518 print("Error: signal handler not called!", file=output)
519 exitcode = 1
Victor Stinner024e37a2011-03-31 01:31:06 +0200520if file is not None:
521 file.close()
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200522sys.exit(exitcode)
Victor Stinner024e37a2011-03-31 01:31:06 +0200523""".strip()
524 code = code.format(
525 filename=repr(filename),
526 has_filename=bool(filename),
527 all_threads=all_threads,
Victor Stinnera01ca122011-04-01 12:56:17 +0200528 signum=signum,
529 unregister=unregister,
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200530 chain=chain,
Victor Stinner024e37a2011-03-31 01:31:06 +0200531 )
Victor Stinner05585cb2011-03-31 13:29:56 +0200532 trace, exitcode = self.get_output(code, filename)
Victor Stinner024e37a2011-03-31 01:31:06 +0200533 trace = '\n'.join(trace)
Victor Stinnera01ca122011-04-01 12:56:17 +0200534 if not unregister:
535 if all_threads:
536 regex = 'Current thread XXX:\n'
537 else:
538 regex = 'Traceback \(most recent call first\):\n'
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200539 regex = expected_traceback(7, 28, regex)
Victor Stinnera01ca122011-04-01 12:56:17 +0200540 self.assertRegex(trace, regex)
Victor Stinner024e37a2011-03-31 01:31:06 +0200541 else:
Victor Stinnera01ca122011-04-01 12:56:17 +0200542 self.assertEqual(trace, '')
543 if unregister:
544 self.assertNotEqual(exitcode, 0)
545 else:
546 self.assertEqual(exitcode, 0)
Victor Stinner024e37a2011-03-31 01:31:06 +0200547
548 def test_register(self):
549 self.check_register()
550
Victor Stinnera01ca122011-04-01 12:56:17 +0200551 def test_unregister(self):
552 self.check_register(unregister=True)
553
Victor Stinner024e37a2011-03-31 01:31:06 +0200554 def test_register_file(self):
555 with temporary_filename() as filename:
556 self.check_register(filename=filename)
557
558 def test_register_threads(self):
559 self.check_register(all_threads=True)
560
Victor Stinnera9a9dab2011-07-13 23:39:53 +0200561 def test_register_chain(self):
562 self.check_register(chain=True)
563
Victor Stinner024e37a2011-03-31 01:31:06 +0200564
565def test_main():
566 support.run_unittest(FaultHandlerTests)
567
568if __name__ == "__main__":
569 test_main()