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