Skip to content

Commit eea6cc4

Browse files
authored
Update the signal + socket libraries + associated tests - v3.13.11 (#6631)
* Updated signal test library * Update socketserve + test library * Fixed test issues with mac * Added sys import into ftplib * Reverted ftplib test changes
1 parent cff37af commit eea6cc4

File tree

3 files changed

+52
-48
lines changed

3 files changed

+52
-48
lines changed

Lib/socketserver.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,7 @@ class will essentially render the service "deaf" while one request is
127127
import selectors
128128
import os
129129
import sys
130-
try:
131-
import threading
132-
except ImportError:
133-
import dummy_threading as threading
130+
import threading
134131
from io import BufferedIOBase
135132
from time import monotonic as time
136133

@@ -144,6 +141,8 @@ class will essentially render the service "deaf" while one request is
144141
__all__.extend(["UnixStreamServer","UnixDatagramServer",
145142
"ThreadingUnixStreamServer",
146143
"ThreadingUnixDatagramServer"])
144+
if hasattr(os, "fork"):
145+
__all__.extend(["ForkingUnixStreamServer", "ForkingUnixDatagramServer"])
147146

148147
# poll/select have the advantage of not requiring any extra file descriptor,
149148
# contrarily to epoll/kqueue (also, they require a single syscall).
@@ -190,6 +189,7 @@ class BaseServer:
190189
- address_family
191190
- socket_type
192191
- allow_reuse_address
192+
- allow_reuse_port
193193
194194
Instance variables:
195195
@@ -294,8 +294,7 @@ def handle_request(self):
294294
selector.register(self, selectors.EVENT_READ)
295295

296296
while True:
297-
ready = selector.select(timeout)
298-
if ready:
297+
if selector.select(timeout):
299298
return self._handle_request_noblock()
300299
else:
301300
if timeout is not None:
@@ -428,6 +427,7 @@ class TCPServer(BaseServer):
428427
- socket_type
429428
- request_queue_size (only for stream sockets)
430429
- allow_reuse_address
430+
- allow_reuse_port
431431
432432
Instance variables:
433433
@@ -445,6 +445,8 @@ class TCPServer(BaseServer):
445445

446446
allow_reuse_address = False
447447

448+
allow_reuse_port = False
449+
448450
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
449451
"""Constructor. May be extended, do not override."""
450452
BaseServer.__init__(self, server_address, RequestHandlerClass)
@@ -464,8 +466,15 @@ def server_bind(self):
464466
May be overridden.
465467
466468
"""
467-
if self.allow_reuse_address:
469+
if self.allow_reuse_address and hasattr(socket, "SO_REUSEADDR"):
468470
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
471+
# Since Linux 6.12.9, SO_REUSEPORT is not allowed
472+
# on other address families than AF_INET/AF_INET6.
473+
if (
474+
self.allow_reuse_port and hasattr(socket, "SO_REUSEPORT")
475+
and self.address_family in (socket.AF_INET, socket.AF_INET6)
476+
):
477+
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
469478
self.socket.bind(self.server_address)
470479
self.server_address = self.socket.getsockname()
471480

@@ -522,6 +531,8 @@ class UDPServer(TCPServer):
522531

523532
allow_reuse_address = False
524533

534+
allow_reuse_port = False
535+
525536
socket_type = socket.SOCK_DGRAM
526537

527538
max_packet_size = 8192
@@ -723,6 +734,11 @@ class ThreadingUnixStreamServer(ThreadingMixIn, UnixStreamServer): pass
723734

724735
class ThreadingUnixDatagramServer(ThreadingMixIn, UnixDatagramServer): pass
725736

737+
if hasattr(os, "fork"):
738+
class ForkingUnixStreamServer(ForkingMixIn, UnixStreamServer): pass
739+
740+
class ForkingUnixDatagramServer(ForkingMixIn, UnixDatagramServer): pass
741+
726742
class BaseRequestHandler:
727743

728744
"""Base class for request handler classes.

Lib/test/test_signal.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
import time
1414
import unittest
1515
from test import support
16-
from test.support import os_helper
16+
from test.support import (
17+
is_apple, is_apple_mobile, os_helper, threading_helper
18+
)
1719
from test.support.script_helper import assert_python_ok, spawn_python
18-
from test.support import threading_helper
1920
try:
2021
import _testcapi
2122
except ImportError:
@@ -122,6 +123,8 @@ def __repr__(self):
122123
self.assertEqual(signal.getsignal(signal.SIGHUP), hup)
123124
self.assertEqual(0, argument.repr_count)
124125

126+
@unittest.skipIf(sys.platform.startswith("netbsd"),
127+
"gh-124083: strsignal is not supported on NetBSD")
125128
def test_strsignal(self):
126129
self.assertIn("Interrupt", signal.strsignal(signal.SIGINT))
127130
self.assertIn("Terminated", signal.strsignal(signal.SIGTERM))
@@ -189,8 +192,7 @@ def test_valid_signals(self):
189192
self.assertNotIn(signal.NSIG, s)
190193
self.assertLess(len(s), signal.NSIG)
191194

192-
# TODO: RUSTPYTHON
193-
@unittest.expectedFailure
195+
@unittest.expectedFailure # TODO: RUSTPYTHON
194196
def test_issue9324(self):
195197
# Updated for issue #10003, adding SIGBREAK
196198
handler = lambda x, y: None
@@ -699,7 +701,7 @@ def handler(signum, frame):
699701
@unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
700702
class SiginterruptTest(unittest.TestCase):
701703

702-
def readpipe_interrupted(self, interrupt):
704+
def readpipe_interrupted(self, interrupt, timeout=support.SHORT_TIMEOUT):
703705
"""Perform a read during which a signal will arrive. Return True if the
704706
read is interrupted by the signal and raises an exception. Return False
705707
if it returns normally.
@@ -747,7 +749,7 @@ def handler(signum, frame):
747749
# wait until the child process is loaded and has started
748750
first_line = process.stdout.readline()
749751

750-
stdout, stderr = process.communicate(timeout=support.SHORT_TIMEOUT)
752+
stdout, stderr = process.communicate(timeout=timeout)
751753
except subprocess.TimeoutExpired:
752754
process.kill()
753755
return False
@@ -778,7 +780,7 @@ def test_siginterrupt_off(self):
778780
# If a signal handler is installed and siginterrupt is called with
779781
# a false value for the second argument, when that signal arrives, it
780782
# does not interrupt a syscall that's in progress.
781-
interrupted = self.readpipe_interrupted(False)
783+
interrupted = self.readpipe_interrupted(False, timeout=2)
782784
self.assertFalse(interrupted)
783785

784786

@@ -834,16 +836,16 @@ def test_itimer_real(self):
834836
self.assertEqual(self.hndl_called, True)
835837

836838
# Issue 3864, unknown if this affects earlier versions of freebsd also
837-
@unittest.skipIf(sys.platform in ('netbsd5',),
839+
@unittest.skipIf(sys.platform in ('netbsd5',) or is_apple_mobile,
838840
'itimer not reliable (does not mix well with threading) on some BSDs.')
839841
def test_itimer_virtual(self):
840842
self.itimer = signal.ITIMER_VIRTUAL
841843
signal.signal(signal.SIGVTALRM, self.sig_vtalrm)
842-
signal.setitimer(self.itimer, 0.3, 0.2)
844+
signal.setitimer(self.itimer, 0.001, 0.001)
843845

844846
for _ in support.busy_retry(support.LONG_TIMEOUT):
845847
# use up some virtual time by doing real work
846-
_ = pow(12345, 67890, 10000019)
848+
_ = sum(i * i for i in range(10**5))
847849
if signal.getitimer(self.itimer) == (0.0, 0.0):
848850
# sig_vtalrm handler stopped this itimer
849851
break
@@ -860,7 +862,7 @@ def test_itimer_prof(self):
860862

861863
for _ in support.busy_retry(support.LONG_TIMEOUT):
862864
# do some work
863-
_ = pow(12345, 67890, 10000019)
865+
_ = sum(i * i for i in range(10**5))
864866
if signal.getitimer(self.itimer) == (0.0, 0.0):
865867
# sig_prof handler stopped this itimer
866868
break
@@ -1326,15 +1328,18 @@ def test_stress_delivery_simultaneous(self):
13261328
def handler(signum, frame):
13271329
sigs.append(signum)
13281330

1329-
self.setsig(signal.SIGUSR1, handler)
1331+
# On Android, SIGUSR1 is unreliable when used in close proximity to
1332+
# another signal – see Android/testbed/app/src/main/python/main.py.
1333+
# So we use a different signal.
1334+
self.setsig(signal.SIGUSR2, handler)
13301335
self.setsig(signal.SIGALRM, handler) # for ITIMER_REAL
13311336

13321337
expected_sigs = 0
13331338
while expected_sigs < N:
13341339
# Hopefully the SIGALRM will be received somewhere during
1335-
# initial processing of SIGUSR1.
1340+
# initial processing of SIGUSR2.
13361341
signal.setitimer(signal.ITIMER_REAL, 1e-6 + random.random() * 1e-5)
1337-
os.kill(os.getpid(), signal.SIGUSR1)
1342+
os.kill(os.getpid(), signal.SIGUSR2)
13381343

13391344
expected_sigs += 2
13401345
# Wait for handlers to run to avoid signal coalescing
@@ -1346,8 +1351,8 @@ def handler(signum, frame):
13461351
# Python handler
13471352
self.assertEqual(len(sigs), N, "Some signals were lost")
13481353

1349-
@unittest.skip("TODO: RUSTPYTHON; hang")
1350-
@unittest.skipIf(sys.platform == "darwin", "crashes due to system bug (FB13453490)")
1354+
@unittest.skip('TODO: RUSTPYTHON; hang')
1355+
@unittest.skipIf(is_apple, "crashes due to system bug (FB13453490)")
13511356
@unittest.skipUnless(hasattr(signal, "SIGUSR1"),
13521357
"test needs SIGUSR1")
13531358
@threading_helper.requires_working_threading()
@@ -1414,8 +1419,7 @@ def test_sigint(self):
14141419
with self.assertRaises(KeyboardInterrupt):
14151420
signal.raise_signal(signal.SIGINT)
14161421

1417-
# TODO: RUSTPYTHON
1418-
@unittest.expectedFailure
1422+
@unittest.expectedFailure # TODO: RUSTPYTHON
14191423
@unittest.skipIf(sys.platform != "win32", "Windows specific test")
14201424
def test_invalid_argument(self):
14211425
try:
@@ -1439,8 +1443,7 @@ def handler(a, b):
14391443
signal.raise_signal(signal.SIGINT)
14401444
self.assertTrue(is_ok)
14411445

1442-
# TODO: RUSTPYTHON
1443-
@unittest.expectedFailure
1446+
@unittest.expectedFailure # TODO: RUSTPYTHON
14441447
def test__thread_interrupt_main(self):
14451448
# See https://github.com/python/cpython/issues/102397
14461449
code = """if 1:

Lib/test/test_socketserver.py

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import select
99
import signal
1010
import socket
11-
import tempfile
1211
import threading
1312
import unittest
1413
import socketserver
@@ -21,21 +20,18 @@
2120

2221

2322
test.support.requires("network")
23+
test.support.requires_working_socket(module=True)
24+
2425

2526
TEST_STR = b"hello world\n"
2627
HOST = socket_helper.HOST
2728

2829
HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX")
2930
requires_unix_sockets = unittest.skipUnless(HAVE_UNIX_SOCKETS,
3031
'requires Unix sockets')
31-
HAVE_FORKING = hasattr(os, "fork")
32+
HAVE_FORKING = test.support.has_fork_support
3233
requires_forking = unittest.skipUnless(HAVE_FORKING, 'requires forking')
3334

34-
def signal_alarm(n):
35-
"""Call signal.alarm when it exists (i.e. not on Windows)."""
36-
if hasattr(signal, 'alarm'):
37-
signal.alarm(n)
38-
3935
# Remember real select() to avoid interferences with mocking
4036
_real_select = select.select
4137

@@ -46,14 +42,6 @@ def receive(sock, n, timeout=test.support.SHORT_TIMEOUT):
4642
else:
4743
raise RuntimeError("timed out on %r" % (sock,))
4844

49-
if HAVE_UNIX_SOCKETS and HAVE_FORKING:
50-
class ForkingUnixStreamServer(socketserver.ForkingMixIn,
51-
socketserver.UnixStreamServer):
52-
pass
53-
54-
class ForkingUnixDatagramServer(socketserver.ForkingMixIn,
55-
socketserver.UnixDatagramServer):
56-
pass
5745

5846
@test.support.requires_fork() # TODO: RUSTPYTHON, os.fork is currently only supported on Unix-based systems
5947
@contextlib.contextmanager
@@ -75,12 +63,10 @@ class SocketServerTest(unittest.TestCase):
7563
"""Test all socket servers."""
7664

7765
def setUp(self):
78-
signal_alarm(60) # Kill deadlocks after 60 seconds.
7966
self.port_seed = 0
8067
self.test_files = []
8168

8269
def tearDown(self):
83-
signal_alarm(0) # Didn't deadlock.
8470
reap_children()
8571

8672
for fn in self.test_files:
@@ -96,8 +82,7 @@ def pickaddr(self, proto):
9682
else:
9783
# XXX: We need a way to tell AF_UNIX to pick its own name
9884
# like AF_INET provides port==0.
99-
dir = None
100-
fn = tempfile.mktemp(prefix='unix_socket.', dir=dir)
85+
fn = socket_helper.create_unix_domain_name()
10186
self.test_files.append(fn)
10287
return fn
10388

@@ -211,7 +196,7 @@ def test_ThreadingUnixStreamServer(self):
211196
@requires_forking
212197
def test_ForkingUnixStreamServer(self):
213198
with simple_subprocess(self):
214-
self.run_server(ForkingUnixStreamServer,
199+
self.run_server(socketserver.ForkingUnixStreamServer,
215200
socketserver.StreamRequestHandler,
216201
self.stream_examine)
217202

@@ -247,7 +232,7 @@ def test_ThreadingUnixDatagramServer(self):
247232
@requires_unix_sockets
248233
@requires_forking
249234
def test_ForkingUnixDatagramServer(self):
250-
self.run_server(ForkingUnixDatagramServer,
235+
self.run_server(socketserver.ForkingUnixDatagramServer,
251236
socketserver.DatagramRequestHandler,
252237
self.dgram_examine)
253238

0 commit comments

Comments
 (0)