Skip to content

Commit fb5354d

Browse files
committed
Merge remote-tracking branch 'upstream/main' into fwdref-format
2 parents 8b776d0 + 5f50541 commit fb5354d

File tree

16 files changed

+225
-76
lines changed

16 files changed

+225
-76
lines changed

Doc/library/fcntl.rst

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -82,65 +82,82 @@ descriptor.
8282
The module defines the following functions:
8383

8484

85-
.. function:: fcntl(fd, cmd, arg=0)
85+
.. function:: fcntl(fd, cmd, arg=0, /)
8686

8787
Perform the operation *cmd* on file descriptor *fd* (file objects providing
8888
a :meth:`~io.IOBase.fileno` method are accepted as well). The values used
8989
for *cmd* are operating system dependent, and are available as constants
9090
in the :mod:`fcntl` module, using the same names as used in the relevant C
91-
header files. The argument *arg* can either be an integer value, or a
92-
:class:`bytes` object. With an integer value, the return value of this
93-
function is the integer return value of the C :c:func:`fcntl` call. When
94-
the argument is bytes it represents a binary structure, e.g. created by
95-
:func:`struct.pack`. The binary data is copied to a buffer whose address is
91+
header files. The argument *arg* can either be an integer value, a
92+
:class:`bytes` object, or a string.
93+
The type and size of *arg* must match the type and size of
94+
the argument of the operation as specified in the relevant C documentation.
95+
96+
When *arg* is an integer, the function returns the integer
97+
return value of the C :c:func:`fcntl` call.
98+
99+
When the argument is bytes, it represents a binary structure,
100+
for example, created by :func:`struct.pack`.
101+
A string value is encoded to binary using the UTF-8 encoding.
102+
The binary data is copied to a buffer whose address is
96103
passed to the C :c:func:`fcntl` call. The return value after a successful
97104
call is the contents of the buffer, converted to a :class:`bytes` object.
98105
The length of the returned object will be the same as the length of the
99-
*arg* argument. This is limited to 1024 bytes. If the information returned
100-
in the buffer by the operating system is larger than 1024 bytes, this is
101-
most likely to result in a segmentation violation or a more subtle data
102-
corruption.
106+
*arg* argument. This is limited to 1024 bytes.
103107

104108
If the :c:func:`fcntl` call fails, an :exc:`OSError` is raised.
105109

110+
.. note::
111+
If the type or the size of *arg* does not match the type or size
112+
of the argument of the operation (for example, if an integer is
113+
passed when a pointer is expected, or the information returned in
114+
the buffer by the operating system is larger than 1024 bytes),
115+
this is most likely to result in a segmentation violation or
116+
a more subtle data corruption.
117+
106118
.. audit-event:: fcntl.fcntl fd,cmd,arg fcntl.fcntl
107119

108120

109-
.. function:: ioctl(fd, request, arg=0, mutate_flag=True)
121+
.. function:: ioctl(fd, request, arg=0, mutate_flag=True, /)
110122

111123
This function is identical to the :func:`~fcntl.fcntl` function, except
112124
that the argument handling is even more complicated.
113125

114-
The *request* parameter is limited to values that can fit in 32-bits.
126+
The *request* parameter is limited to values that can fit in 32-bits
127+
or 64-bits, depending on the platform.
115128
Additional constants of interest for use as the *request* argument can be
116129
found in the :mod:`termios` module, under the same names as used in
117130
the relevant C header files.
118131

119-
The parameter *arg* can be one of an integer, an object supporting the
120-
read-only buffer interface (like :class:`bytes`) or an object supporting
121-
the read-write buffer interface (like :class:`bytearray`).
132+
The parameter *arg* can be an integer, a :term:`bytes-like object`,
133+
or a string.
134+
The type and size of *arg* must match the type and size of
135+
the argument of the operation as specified in the relevant C documentation.
122136

123-
In all but the last case, behaviour is as for the :func:`~fcntl.fcntl`
137+
If *arg* does not support the read-write buffer interface or
138+
the *mutate_flag* is false, behavior is as for the :func:`~fcntl.fcntl`
124139
function.
125140

126-
If a mutable buffer is passed, then the behaviour is determined by the value of
127-
the *mutate_flag* parameter.
128-
129-
If it is false, the buffer's mutability is ignored and behaviour is as for a
130-
read-only buffer, except that the 1024 byte limit mentioned above is avoided --
131-
so long as the buffer you pass is at least as long as what the operating system
132-
wants to put there, things should work.
133-
134-
If *mutate_flag* is true (the default), then the buffer is (in effect) passed
135-
to the underlying :func:`ioctl` system call, the latter's return code is
141+
If *arg* supports the read-write buffer interface (like :class:`bytearray`)
142+
and *mutate_flag* is true (the default), then the buffer is (in effect) passed
143+
to the underlying :c:func:`!ioctl` system call, the latter's return code is
136144
passed back to the calling Python, and the buffer's new contents reflect the
137-
action of the :func:`ioctl`. This is a slight simplification, because if the
145+
action of the :c:func:`ioctl`. This is a slight simplification, because if the
138146
supplied buffer is less than 1024 bytes long it is first copied into a static
139147
buffer 1024 bytes long which is then passed to :func:`ioctl` and copied back
140148
into the supplied buffer.
141149

142150
If the :c:func:`ioctl` call fails, an :exc:`OSError` exception is raised.
143151

152+
.. note::
153+
If the type or size of *arg* does not match the type or size
154+
of the operation's argument (for example, if an integer is
155+
passed when a pointer is expected, or the information returned in
156+
the buffer by the operating system is larger than 1024 bytes,
157+
or the size of the mutable bytes-like object is too small),
158+
this is most likely to result in a segmentation violation or
159+
a more subtle data corruption.
160+
144161
An example::
145162

146163
>>> import array, fcntl, struct, termios, os
@@ -157,7 +174,7 @@ The module defines the following functions:
157174
.. audit-event:: fcntl.ioctl fd,request,arg fcntl.ioctl
158175

159176

160-
.. function:: flock(fd, operation)
177+
.. function:: flock(fd, operation, /)
161178

162179
Perform the lock operation *operation* on file descriptor *fd* (file objects providing
163180
a :meth:`~io.IOBase.fileno` method are accepted as well). See the Unix manual
@@ -169,7 +186,7 @@ The module defines the following functions:
169186
.. audit-event:: fcntl.flock fd,operation fcntl.flock
170187

171188

172-
.. function:: lockf(fd, cmd, len=0, start=0, whence=0)
189+
.. function:: lockf(fd, cmd, len=0, start=0, whence=0, /)
173190

174191
This is essentially a wrapper around the :func:`~fcntl.fcntl` locking calls.
175192
*fd* is the file descriptor (file objects providing a :meth:`~io.IOBase.fileno`

Doc/library/multiprocessing.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,25 @@ The :mod:`multiprocessing` package mostly replicates the API of the
670670

671671
.. versionadded:: 3.3
672672

673+
.. method:: interrupt()
674+
675+
Terminate the process. Works on POSIX using the :py:const:`~signal.SIGINT` signal.
676+
Behavior on Windows is undefined.
677+
678+
By default, this terminates the child process by raising :exc:`KeyboardInterrupt`.
679+
This behavior can be altered by setting the respective signal handler in the child
680+
process :func:`signal.signal` for :py:const:`~signal.SIGINT`.
681+
682+
Note: if the child process catches and discards :exc:`KeyboardInterrupt`, the
683+
process will not be terminated.
684+
685+
Note: the default behavior will also set :attr:`exitcode` to ``1`` as if an
686+
uncaught exception was raised in the child process. To have a different
687+
:attr:`exitcode` you may simply catch :exc:`KeyboardInterrupt` and call
688+
``exit(your_code)``.
689+
690+
.. versionadded:: next
691+
673692
.. method:: terminate()
674693

675694
Terminate the process. On POSIX this is done using the :py:const:`~signal.SIGTERM` signal;

Doc/whatsnew/3.14.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,10 @@ multiprocessing
972972
The :func:`set` in :func:`multiprocessing.Manager` method is now available.
973973
(Contributed by Mingyu Park in :gh:`129949`.)
974974

975+
* Add :func:`multiprocessing.Process.interrupt` which terminates the child
976+
process by sending :py:const:`~signal.SIGINT`. This enables "finally" clauses
977+
and printing stack trace for the terminated process.
978+
(Contributed by Artem Pulkin in :gh:`131913`.)
975979

976980
operator
977981
--------

Lib/multiprocessing/popen_fork.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ def _send_signal(self, sig):
5454
if self.wait(timeout=0.1) is None:
5555
raise
5656

57+
def interrupt(self):
58+
self._send_signal(signal.SIGINT)
59+
5760
def terminate(self):
5861
self._send_signal(signal.SIGTERM)
5962

Lib/multiprocessing/process.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ def start(self):
125125
del self._target, self._args, self._kwargs
126126
_children.add(self)
127127

128+
def interrupt(self):
129+
'''
130+
Terminate process; sends SIGINT signal
131+
'''
132+
self._check_closed()
133+
self._popen.interrupt()
134+
128135
def terminate(self):
129136
'''
130137
Terminate process; sends SIGTERM signal or uses TerminateProcess()

Lib/test/_test_multiprocessing.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,15 +512,20 @@ def _test_process_mainthread_native_id(cls, q):
512512
def _sleep_some(cls):
513513
time.sleep(100)
514514

515+
@classmethod
516+
def _sleep_no_int_handler(cls):
517+
signal.signal(signal.SIGINT, signal.SIG_DFL)
518+
cls._sleep_some()
519+
515520
@classmethod
516521
def _test_sleep(cls, delay):
517522
time.sleep(delay)
518523

519-
def _kill_process(self, meth):
524+
def _kill_process(self, meth, target=None):
520525
if self.TYPE == 'threads':
521526
self.skipTest('test not appropriate for {}'.format(self.TYPE))
522527

523-
p = self.Process(target=self._sleep_some)
528+
p = self.Process(target=target or self._sleep_some)
524529
p.daemon = True
525530
p.start()
526531

@@ -567,6 +572,19 @@ def handler(*args):
567572

568573
return p.exitcode
569574

575+
@unittest.skipIf(os.name == 'nt', "POSIX only")
576+
def test_interrupt(self):
577+
exitcode = self._kill_process(multiprocessing.Process.interrupt)
578+
self.assertEqual(exitcode, 1)
579+
# exit code 1 is hard-coded for uncaught exceptions
580+
# (KeyboardInterrupt in this case)
581+
# in multiprocessing.BaseProcess._bootstrap
582+
583+
@unittest.skipIf(os.name == 'nt', "POSIX only")
584+
def test_interrupt_no_handler(self):
585+
exitcode = self._kill_process(multiprocessing.Process.interrupt, target=self._sleep_no_int_handler)
586+
self.assertEqual(exitcode, -signal.SIGINT)
587+
570588
def test_terminate(self):
571589
exitcode = self._kill_process(multiprocessing.Process.terminate)
572590
self.assertEqual(exitcode, -signal.SIGTERM)

Lib/test/support/os_helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ def fd_count():
657657
"""
658658
if sys.platform.startswith(('linux', 'android', 'freebsd', 'emscripten')):
659659
fd_path = "/proc/self/fd"
660-
elif sys.platform == "darwin":
660+
elif support.is_apple:
661661
fd_path = "/dev/fd"
662662
else:
663663
fd_path = None

Lib/test/test_socket.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2647,14 +2647,13 @@ def testBluetoothConstants(self):
26472647
socket.BT_POWER
26482648
socket.BT_CHANNEL_POLICY
26492649
socket.BT_CHANNEL_POLICY_BREDR_ONLY
2650-
socket.BT_PHY
2651-
socket.BT_PHY_BR_1M_1SLOT
2652-
socket.BT_MODE
2653-
socket.BT_MODE_BASIC
2654-
socket.BT_VOICE
2655-
socket.BT_VOICE_TRANSPARENT
2656-
socket.BT_VOICE_CVSD_16BIT
2657-
socket.BT_CODEC
2650+
if hasattr(socket, 'BT_PHY'):
2651+
socket.BT_PHY_BR_1M_1SLOT
2652+
if hasattr(socket, 'BT_MODE'):
2653+
socket.BT_MODE_BASIC
2654+
if hasattr(socket, 'BT_VOICE'):
2655+
socket.BT_VOICE_TRANSPARENT
2656+
socket.BT_VOICE_CVSD_16BIT
26582657
socket.L2CAP_LM
26592658
socket.L2CAP_LM_MASTER
26602659
socket.L2CAP_LM_AUTH
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix building with tail call interpreter and pystats.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add a shortcut function :func:`multiprocessing.Process.interrupt` alongside the existing :func:`multiprocessing.Process.terminate` and :func:`multiprocessing.Process.kill` for an improved control over child process termination.

0 commit comments

Comments
 (0)