|
10 | 10 | import os
|
11 | 11 | import pickle
|
12 | 12 | import random
|
13 |
| -import signal |
14 | 13 | import sys
|
15 | 14 | import textwrap
|
16 | 15 | import threading
|
@@ -39,9 +38,6 @@ def _default_chunk_size():
|
39 | 38 | with open(__file__, "r", encoding="latin-1") as f:
|
40 | 39 | return f._CHUNK_SIZE
|
41 | 40 |
|
42 |
| -requires_alarm = unittest.skipUnless( |
43 |
| - hasattr(signal, "alarm"), "test requires signal.alarm()" |
44 |
| -) |
45 | 41 |
|
46 | 42 |
|
47 | 43 | class BadIndex:
|
@@ -4468,273 +4464,6 @@ class PyMiscIOTest(MiscIOTest, PyTestCase):
|
4468 | 4464 | not_exported = "valid_seek_flags",
|
4469 | 4465 |
|
4470 | 4466 |
|
4471 |
| -@unittest.skipIf(os.name == 'nt', 'POSIX signals required for this test.') |
4472 |
| -class SignalsTest: |
4473 |
| - |
4474 |
| - def setUp(self): |
4475 |
| - self.oldalrm = signal.signal(signal.SIGALRM, self.alarm_interrupt) |
4476 |
| - |
4477 |
| - def tearDown(self): |
4478 |
| - signal.signal(signal.SIGALRM, self.oldalrm) |
4479 |
| - |
4480 |
| - def alarm_interrupt(self, sig, frame): |
4481 |
| - 1/0 |
4482 |
| - |
4483 |
| - def check_interrupted_write(self, item, bytes, **fdopen_kwargs): |
4484 |
| - """Check that a partial write, when it gets interrupted, properly |
4485 |
| - invokes the signal handler, and bubbles up the exception raised |
4486 |
| - in the latter.""" |
4487 |
| - |
4488 |
| - # XXX This test has three flaws that appear when objects are |
4489 |
| - # XXX not reference counted. |
4490 |
| - |
4491 |
| - # - if wio.write() happens to trigger a garbage collection, |
4492 |
| - # the signal exception may be raised when some __del__ |
4493 |
| - # method is running; it will not reach the assertRaises() |
4494 |
| - # call. |
4495 |
| - |
4496 |
| - # - more subtle, if the wio object is not destroyed at once |
4497 |
| - # and survives this function, the next opened file is likely |
4498 |
| - # to have the same fileno (since the file descriptor was |
4499 |
| - # actively closed). When wio.__del__ is finally called, it |
4500 |
| - # will close the other's test file... To trigger this with |
4501 |
| - # CPython, try adding "global wio" in this function. |
4502 |
| - |
4503 |
| - # - This happens only for streams created by the _pyio module, |
4504 |
| - # because a wio.close() that fails still consider that the |
4505 |
| - # file needs to be closed again. You can try adding an |
4506 |
| - # "assert wio.closed" at the end of the function. |
4507 |
| - |
4508 |
| - # Fortunately, a little gc.collect() seems to be enough to |
4509 |
| - # work around all these issues. |
4510 |
| - support.gc_collect() # For PyPy or other GCs. |
4511 |
| - |
4512 |
| - read_results = [] |
4513 |
| - def _read(): |
4514 |
| - s = os.read(r, 1) |
4515 |
| - read_results.append(s) |
4516 |
| - |
4517 |
| - t = threading.Thread(target=_read) |
4518 |
| - t.daemon = True |
4519 |
| - r, w = os.pipe() |
4520 |
| - fdopen_kwargs["closefd"] = False |
4521 |
| - large_data = item * (support.PIPE_MAX_SIZE // len(item) + 1) |
4522 |
| - try: |
4523 |
| - wio = self.io.open(w, **fdopen_kwargs) |
4524 |
| - if hasattr(signal, 'pthread_sigmask'): |
4525 |
| - # create the thread with SIGALRM signal blocked |
4526 |
| - signal.pthread_sigmask(signal.SIG_BLOCK, [signal.SIGALRM]) |
4527 |
| - t.start() |
4528 |
| - signal.pthread_sigmask(signal.SIG_UNBLOCK, [signal.SIGALRM]) |
4529 |
| - else: |
4530 |
| - t.start() |
4531 |
| - |
4532 |
| - # Fill the pipe enough that the write will be blocking. |
4533 |
| - # It will be interrupted by the timer armed above. Since the |
4534 |
| - # other thread has read one byte, the low-level write will |
4535 |
| - # return with a successful (partial) result rather than an EINTR. |
4536 |
| - # The buffered IO layer must check for pending signal |
4537 |
| - # handlers, which in this case will invoke alarm_interrupt(). |
4538 |
| - signal.alarm(1) |
4539 |
| - try: |
4540 |
| - self.assertRaises(ZeroDivisionError, wio.write, large_data) |
4541 |
| - finally: |
4542 |
| - signal.alarm(0) |
4543 |
| - t.join() |
4544 |
| - # We got one byte, get another one and check that it isn't a |
4545 |
| - # repeat of the first one. |
4546 |
| - read_results.append(os.read(r, 1)) |
4547 |
| - self.assertEqual(read_results, [bytes[0:1], bytes[1:2]]) |
4548 |
| - finally: |
4549 |
| - os.close(w) |
4550 |
| - os.close(r) |
4551 |
| - # This is deliberate. If we didn't close the file descriptor |
4552 |
| - # before closing wio, wio would try to flush its internal |
4553 |
| - # buffer, and block again. |
4554 |
| - try: |
4555 |
| - wio.close() |
4556 |
| - except OSError as e: |
4557 |
| - if e.errno != errno.EBADF: |
4558 |
| - raise |
4559 |
| - |
4560 |
| - @requires_alarm |
4561 |
| - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") |
4562 |
| - def test_interrupted_write_unbuffered(self): |
4563 |
| - self.check_interrupted_write(b"xy", b"xy", mode="wb", buffering=0) |
4564 |
| - |
4565 |
| - @requires_alarm |
4566 |
| - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") |
4567 |
| - def test_interrupted_write_buffered(self): |
4568 |
| - self.check_interrupted_write(b"xy", b"xy", mode="wb") |
4569 |
| - |
4570 |
| - @requires_alarm |
4571 |
| - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") |
4572 |
| - def test_interrupted_write_text(self): |
4573 |
| - self.check_interrupted_write("xy", b"xy", mode="w", encoding="ascii") |
4574 |
| - |
4575 |
| - @support.no_tracing |
4576 |
| - def check_reentrant_write(self, data, **fdopen_kwargs): |
4577 |
| - def on_alarm(*args): |
4578 |
| - # Will be called reentrantly from the same thread |
4579 |
| - wio.write(data) |
4580 |
| - 1/0 |
4581 |
| - signal.signal(signal.SIGALRM, on_alarm) |
4582 |
| - r, w = os.pipe() |
4583 |
| - wio = self.io.open(w, **fdopen_kwargs) |
4584 |
| - try: |
4585 |
| - signal.alarm(1) |
4586 |
| - # Either the reentrant call to wio.write() fails with RuntimeError, |
4587 |
| - # or the signal handler raises ZeroDivisionError. |
4588 |
| - with self.assertRaises((ZeroDivisionError, RuntimeError)) as cm: |
4589 |
| - while 1: |
4590 |
| - for i in range(100): |
4591 |
| - wio.write(data) |
4592 |
| - wio.flush() |
4593 |
| - # Make sure the buffer doesn't fill up and block further writes |
4594 |
| - os.read(r, len(data) * 100) |
4595 |
| - exc = cm.exception |
4596 |
| - if isinstance(exc, RuntimeError): |
4597 |
| - self.assertStartsWith(str(exc), "reentrant call") |
4598 |
| - finally: |
4599 |
| - signal.alarm(0) |
4600 |
| - wio.close() |
4601 |
| - os.close(r) |
4602 |
| - |
4603 |
| - @requires_alarm |
4604 |
| - def test_reentrant_write_buffered(self): |
4605 |
| - self.check_reentrant_write(b"xy", mode="wb") |
4606 |
| - |
4607 |
| - @requires_alarm |
4608 |
| - def test_reentrant_write_text(self): |
4609 |
| - self.check_reentrant_write("xy", mode="w", encoding="ascii") |
4610 |
| - |
4611 |
| - def check_interrupted_read_retry(self, decode, **fdopen_kwargs): |
4612 |
| - """Check that a buffered read, when it gets interrupted (either |
4613 |
| - returning a partial result or EINTR), properly invokes the signal |
4614 |
| - handler and retries if the latter returned successfully.""" |
4615 |
| - r, w = os.pipe() |
4616 |
| - fdopen_kwargs["closefd"] = False |
4617 |
| - def alarm_handler(sig, frame): |
4618 |
| - os.write(w, b"bar") |
4619 |
| - signal.signal(signal.SIGALRM, alarm_handler) |
4620 |
| - try: |
4621 |
| - rio = self.io.open(r, **fdopen_kwargs) |
4622 |
| - os.write(w, b"foo") |
4623 |
| - signal.alarm(1) |
4624 |
| - # Expected behaviour: |
4625 |
| - # - first raw read() returns partial b"foo" |
4626 |
| - # - second raw read() returns EINTR |
4627 |
| - # - third raw read() returns b"bar" |
4628 |
| - self.assertEqual(decode(rio.read(6)), "foobar") |
4629 |
| - finally: |
4630 |
| - signal.alarm(0) |
4631 |
| - rio.close() |
4632 |
| - os.close(w) |
4633 |
| - os.close(r) |
4634 |
| - |
4635 |
| - @requires_alarm |
4636 |
| - @support.requires_resource('walltime') |
4637 |
| - def test_interrupted_read_retry_buffered(self): |
4638 |
| - self.check_interrupted_read_retry(lambda x: x.decode('latin1'), |
4639 |
| - mode="rb") |
4640 |
| - |
4641 |
| - @requires_alarm |
4642 |
| - @support.requires_resource('walltime') |
4643 |
| - def test_interrupted_read_retry_text(self): |
4644 |
| - self.check_interrupted_read_retry(lambda x: x, |
4645 |
| - mode="r", encoding="latin1") |
4646 |
| - |
4647 |
| - def check_interrupted_write_retry(self, item, **fdopen_kwargs): |
4648 |
| - """Check that a buffered write, when it gets interrupted (either |
4649 |
| - returning a partial result or EINTR), properly invokes the signal |
4650 |
| - handler and retries if the latter returned successfully.""" |
4651 |
| - select = import_helper.import_module("select") |
4652 |
| - |
4653 |
| - # A quantity that exceeds the buffer size of an anonymous pipe's |
4654 |
| - # write end. |
4655 |
| - N = support.PIPE_MAX_SIZE |
4656 |
| - r, w = os.pipe() |
4657 |
| - fdopen_kwargs["closefd"] = False |
4658 |
| - |
4659 |
| - # We need a separate thread to read from the pipe and allow the |
4660 |
| - # write() to finish. This thread is started after the SIGALRM is |
4661 |
| - # received (forcing a first EINTR in write()). |
4662 |
| - read_results = [] |
4663 |
| - write_finished = False |
4664 |
| - error = None |
4665 |
| - def _read(): |
4666 |
| - try: |
4667 |
| - while not write_finished: |
4668 |
| - while r in select.select([r], [], [], 1.0)[0]: |
4669 |
| - s = os.read(r, 1024) |
4670 |
| - read_results.append(s) |
4671 |
| - except BaseException as exc: |
4672 |
| - nonlocal error |
4673 |
| - error = exc |
4674 |
| - t = threading.Thread(target=_read) |
4675 |
| - t.daemon = True |
4676 |
| - def alarm1(sig, frame): |
4677 |
| - signal.signal(signal.SIGALRM, alarm2) |
4678 |
| - signal.alarm(1) |
4679 |
| - def alarm2(sig, frame): |
4680 |
| - t.start() |
4681 |
| - |
4682 |
| - large_data = item * N |
4683 |
| - signal.signal(signal.SIGALRM, alarm1) |
4684 |
| - try: |
4685 |
| - wio = self.io.open(w, **fdopen_kwargs) |
4686 |
| - signal.alarm(1) |
4687 |
| - # Expected behaviour: |
4688 |
| - # - first raw write() is partial (because of the limited pipe buffer |
4689 |
| - # and the first alarm) |
4690 |
| - # - second raw write() returns EINTR (because of the second alarm) |
4691 |
| - # - subsequent write()s are successful (either partial or complete) |
4692 |
| - written = wio.write(large_data) |
4693 |
| - self.assertEqual(N, written) |
4694 |
| - |
4695 |
| - wio.flush() |
4696 |
| - write_finished = True |
4697 |
| - t.join() |
4698 |
| - |
4699 |
| - self.assertIsNone(error) |
4700 |
| - self.assertEqual(N, sum(len(x) for x in read_results)) |
4701 |
| - finally: |
4702 |
| - signal.alarm(0) |
4703 |
| - write_finished = True |
4704 |
| - os.close(w) |
4705 |
| - os.close(r) |
4706 |
| - # This is deliberate. If we didn't close the file descriptor |
4707 |
| - # before closing wio, wio would try to flush its internal |
4708 |
| - # buffer, and could block (in case of failure). |
4709 |
| - try: |
4710 |
| - wio.close() |
4711 |
| - except OSError as e: |
4712 |
| - if e.errno != errno.EBADF: |
4713 |
| - raise |
4714 |
| - |
4715 |
| - @requires_alarm |
4716 |
| - @support.requires_resource('walltime') |
4717 |
| - def test_interrupted_write_retry_buffered(self): |
4718 |
| - self.check_interrupted_write_retry(b"x", mode="wb") |
4719 |
| - |
4720 |
| - @requires_alarm |
4721 |
| - @support.requires_resource('walltime') |
4722 |
| - def test_interrupted_write_retry_text(self): |
4723 |
| - self.check_interrupted_write_retry("x", mode="w", encoding="latin1") |
4724 |
| - |
4725 |
| - |
4726 |
| -class CSignalsTest(SignalsTest, CTestCase): |
4727 |
| - pass |
4728 |
| - |
4729 |
| -class PySignalsTest(SignalsTest, PyTestCase): |
4730 |
| - pass |
4731 |
| - |
4732 |
| - # Handling reentrancy issues would slow down _pyio even more, so the |
4733 |
| - # tests are disabled. |
4734 |
| - test_reentrant_write_buffered = None |
4735 |
| - test_reentrant_write_text = None |
4736 |
| - |
4737 |
| - |
4738 | 4467 | class ProtocolsTest(unittest.TestCase):
|
4739 | 4468 | class MyReader:
|
4740 | 4469 | def read(self, sz=-1):
|
|
0 commit comments