|
6 | 6 | import pickle |
7 | 7 | import select |
8 | 8 | import signal |
| 9 | +import socket |
9 | 10 | import struct |
10 | 11 | import subprocess |
11 | 12 | import traceback |
@@ -251,21 +252,43 @@ def test_issue9324(self): |
251 | 252 | class WakeupFDTests(unittest.TestCase): |
252 | 253 |
|
253 | 254 | def test_invalid_fd(self): |
254 | | - fd = support.make_bad_fd() |
| 255 | + if sys.platform == "win32": |
| 256 | + sock = socket.socket() |
| 257 | + fd = sock.fileno() |
| 258 | + sock.close() |
| 259 | + else: |
| 260 | + fd = support.make_bad_fd() |
255 | 261 | self.assertRaises((ValueError, OSError), |
256 | 262 | signal.set_wakeup_fd, fd) |
257 | 263 |
|
| 264 | + @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') |
| 265 | + def test_only_socket(self): |
| 266 | + # set_wakeup_fd() expects a socket on Windows |
| 267 | + with open(support.TESTFN, 'wb') as fp: |
| 268 | + self.addCleanup(support.unlink, support.TESTFN) |
| 269 | + self.assertRaises(ValueError, |
| 270 | + signal.set_wakeup_fd, fp.fileno()) |
| 271 | + |
258 | 272 | def test_set_wakeup_fd_result(self): |
259 | | - r1, w1 = os.pipe() |
260 | | - self.addCleanup(os.close, r1) |
261 | | - self.addCleanup(os.close, w1) |
262 | | - r2, w2 = os.pipe() |
263 | | - self.addCleanup(os.close, r2) |
264 | | - self.addCleanup(os.close, w2) |
265 | | - |
266 | | - signal.set_wakeup_fd(w1) |
267 | | - self.assertIs(signal.set_wakeup_fd(w2), w1) |
268 | | - self.assertIs(signal.set_wakeup_fd(-1), w2) |
| 273 | + if sys.platform == 'win32': |
| 274 | + sock1 = socket.socket() |
| 275 | + self.addCleanup(sock1.close) |
| 276 | + fd1 = sock1.fileno() |
| 277 | + |
| 278 | + sock2 = socket.socket() |
| 279 | + self.addCleanup(sock2.close) |
| 280 | + fd2 = sock2.fileno() |
| 281 | + else: |
| 282 | + r1, fd1 = os.pipe() |
| 283 | + self.addCleanup(os.close, r1) |
| 284 | + self.addCleanup(os.close, fd1) |
| 285 | + r2, fd2 = os.pipe() |
| 286 | + self.addCleanup(os.close, r2) |
| 287 | + self.addCleanup(os.close, fd2) |
| 288 | + |
| 289 | + signal.set_wakeup_fd(fd1) |
| 290 | + self.assertIs(signal.set_wakeup_fd(fd2), fd1) |
| 291 | + self.assertIs(signal.set_wakeup_fd(-1), fd2) |
269 | 292 | self.assertIs(signal.set_wakeup_fd(-1), -1) |
270 | 293 |
|
271 | 294 |
|
@@ -441,6 +464,90 @@ def test_pending(self): |
441 | 464 | """, signal.SIGUSR1, signal.SIGUSR2, ordered=False) |
442 | 465 |
|
443 | 466 |
|
| 467 | +@unittest.skipUnless(hasattr(socket, 'socketpair'), 'need socket.socketpair') |
| 468 | +class WakeupSocketSignalTests(unittest.TestCase): |
| 469 | + |
| 470 | + @unittest.skipIf(_testcapi is None, 'need _testcapi') |
| 471 | + def test_socket(self): |
| 472 | + # use a subprocess to have only one thread |
| 473 | + code = """if 1: |
| 474 | + import signal |
| 475 | + import socket |
| 476 | + import struct |
| 477 | + import _testcapi |
| 478 | +
|
| 479 | + signum = signal.SIGINT |
| 480 | + signals = (signum,) |
| 481 | +
|
| 482 | + def handler(signum, frame): |
| 483 | + pass |
| 484 | +
|
| 485 | + signal.signal(signum, handler) |
| 486 | +
|
| 487 | + read, write = socket.socketpair() |
| 488 | + read.setblocking(False) |
| 489 | + write.setblocking(False) |
| 490 | + signal.set_wakeup_fd(write.fileno()) |
| 491 | +
|
| 492 | + _testcapi.raise_signal(signum) |
| 493 | +
|
| 494 | + data = read.recv(1) |
| 495 | + if not data: |
| 496 | + raise Exception("no signum written") |
| 497 | + raised = struct.unpack('B', data) |
| 498 | + if raised != signals: |
| 499 | + raise Exception("%r != %r" % (raised, signals)) |
| 500 | +
|
| 501 | + read.close() |
| 502 | + write.close() |
| 503 | + """ |
| 504 | + |
| 505 | + assert_python_ok('-c', code) |
| 506 | + |
| 507 | + @unittest.skipIf(_testcapi is None, 'need _testcapi') |
| 508 | + def test_send_error(self): |
| 509 | + # Use a subprocess to have only one thread. |
| 510 | + if os.name == 'nt': |
| 511 | + action = 'send' |
| 512 | + else: |
| 513 | + action = 'write' |
| 514 | + code = """if 1: |
| 515 | + import errno |
| 516 | + import signal |
| 517 | + import socket |
| 518 | + import sys |
| 519 | + import time |
| 520 | + import _testcapi |
| 521 | + from test.support import captured_stderr |
| 522 | +
|
| 523 | + signum = signal.SIGINT |
| 524 | +
|
| 525 | + def handler(signum, frame): |
| 526 | + pass |
| 527 | +
|
| 528 | + signal.signal(signum, handler) |
| 529 | +
|
| 530 | + read, write = socket.socketpair() |
| 531 | + read.setblocking(False) |
| 532 | + write.setblocking(False) |
| 533 | +
|
| 534 | + signal.set_wakeup_fd(write.fileno()) |
| 535 | +
|
| 536 | + # Close sockets: send() will fail |
| 537 | + read.close() |
| 538 | + write.close() |
| 539 | +
|
| 540 | + with captured_stderr() as err: |
| 541 | + _testcapi.raise_signal(signum) |
| 542 | +
|
| 543 | + err = err.getvalue() |
| 544 | + if ('Exception ignored when trying to {action} to the signal wakeup fd' |
| 545 | + not in err): |
| 546 | + raise AssertionError(err) |
| 547 | + """.format(action=action) |
| 548 | + assert_python_ok('-c', code) |
| 549 | + |
| 550 | + |
444 | 551 | @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") |
445 | 552 | class SiginterruptTest(unittest.TestCase): |
446 | 553 |
|
@@ -990,6 +1097,7 @@ def test_main(): |
990 | 1097 | try: |
991 | 1098 | support.run_unittest(GenericTests, PosixTests, InterProcessSignalTests, |
992 | 1099 | WakeupFDTests, WakeupSignalTests, |
| 1100 | + WakeupSocketSignalTests, |
993 | 1101 | SiginterruptTest, ItimerTest, WindowsSignalTests, |
994 | 1102 | PendingSignalsTests) |
995 | 1103 | finally: |
|
0 commit comments