66import pickle
77import select
88import signal
9+ import socket
910import struct
1011import subprocess
1112import traceback
@@ -255,6 +256,13 @@ def test_invalid_fd(self):
255256 self .assertRaises ((ValueError , OSError ),
256257 signal .set_wakeup_fd , fd )
257258
259+ def test_invalid_socket (self ):
260+ sock = socket .socket ()
261+ fd = sock .fileno ()
262+ sock .close ()
263+ self .assertRaises ((ValueError , OSError ),
264+ signal .set_wakeup_fd , fd )
265+
258266 def test_set_wakeup_fd_result (self ):
259267 r1 , w1 = os .pipe ()
260268 self .addCleanup (os .close , r1 )
@@ -268,6 +276,20 @@ def test_set_wakeup_fd_result(self):
268276 self .assertEqual (signal .set_wakeup_fd (- 1 ), w2 )
269277 self .assertEqual (signal .set_wakeup_fd (- 1 ), - 1 )
270278
279+ def test_set_wakeup_fd_socket_result (self ):
280+ sock1 = socket .socket ()
281+ self .addCleanup (sock1 .close )
282+ fd1 = sock1 .fileno ()
283+
284+ sock2 = socket .socket ()
285+ self .addCleanup (sock2 .close )
286+ fd2 = sock2 .fileno ()
287+
288+ signal .set_wakeup_fd (fd1 )
289+ self .assertIs (signal .set_wakeup_fd (fd2 ), fd1 )
290+ self .assertIs (signal .set_wakeup_fd (- 1 ), fd2 )
291+ self .assertIs (signal .set_wakeup_fd (- 1 ), - 1 )
292+
271293
272294@unittest .skipIf (sys .platform == "win32" , "Not valid on Windows" )
273295class WakeupSignalTests (unittest .TestCase ):
@@ -435,6 +457,90 @@ def test_pending(self):
435457 """ , signal .SIGUSR1 , signal .SIGUSR2 , ordered = False )
436458
437459
460+ @unittest .skipUnless (hasattr (socket , 'socketpair' ), 'need socket.socketpair' )
461+ class WakeupSocketSignalTests (unittest .TestCase ):
462+
463+ @unittest .skipIf (_testcapi is None , 'need _testcapi' )
464+ def test_socket (self ):
465+ # use a subprocess to have only one thread
466+ code = """if 1:
467+ import signal
468+ import socket
469+ import struct
470+ import _testcapi
471+
472+ signum = signal.SIGINT
473+ signals = (signum,)
474+
475+ def handler(signum, frame):
476+ pass
477+
478+ signal.signal(signum, handler)
479+
480+ read, write = socket.socketpair()
481+ read.setblocking(False)
482+ write.setblocking(False)
483+ signal.set_wakeup_fd(write.fileno())
484+
485+ _testcapi.raise_signal(signum)
486+
487+ data = read.recv(1)
488+ if not data:
489+ raise Exception("no signum written")
490+ raised = struct.unpack('B', data)
491+ if raised != signals:
492+ raise Exception("%r != %r" % (raised, signals))
493+
494+ read.close()
495+ write.close()
496+ """
497+
498+ assert_python_ok ('-c' , code )
499+
500+ @unittest .skipIf (_testcapi is None , 'need _testcapi' )
501+ def test_send_error (self ):
502+ # Use a subprocess to have only one thread.
503+ if os .name == 'nt' :
504+ action = 'send'
505+ else :
506+ action = 'write'
507+ code = """if 1:
508+ import errno
509+ import signal
510+ import socket
511+ import sys
512+ import time
513+ import _testcapi
514+ from test.support import captured_stderr
515+
516+ signum = signal.SIGINT
517+
518+ def handler(signum, frame):
519+ pass
520+
521+ signal.signal(signum, handler)
522+
523+ read, write = socket.socketpair()
524+ read.setblocking(False)
525+ write.setblocking(False)
526+
527+ signal.set_wakeup_fd(write.fileno())
528+
529+ # Close sockets: send() will fail
530+ read.close()
531+ write.close()
532+
533+ with captured_stderr() as err:
534+ _testcapi.raise_signal(signum)
535+
536+ err = err.getvalue()
537+ if ('Exception ignored when trying to {action} to the signal wakeup fd'
538+ not in err):
539+ raise AssertionError(err)
540+ """ .format (action = action )
541+ assert_python_ok ('-c' , code )
542+
543+
438544@unittest .skipIf (sys .platform == "win32" , "Not valid on Windows" )
439545class SiginterruptTest (unittest .TestCase ):
440546
@@ -984,6 +1090,7 @@ def test_main():
9841090 try :
9851091 support .run_unittest (GenericTests , PosixTests , InterProcessSignalTests ,
9861092 WakeupFDTests , WakeupSignalTests ,
1093+ WakeupSocketSignalTests ,
9871094 SiginterruptTest , ItimerTest , WindowsSignalTests ,
9881095 PendingSignalsTests )
9891096 finally :
0 commit comments