Skip to content

Commit 4959a6a

Browse files
committed
Merge branch 'main' into pr/92078
2 parents f9d468c + af3f6fc commit 4959a6a

File tree

9 files changed

+168
-161
lines changed

9 files changed

+168
-161
lines changed

Lib/test/test_ioctl.py

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import array
22
import os
33
import struct
4+
import sys
45
import threading
56
import unittest
67
from test.support import get_attribute
@@ -139,11 +140,55 @@ def setUp(self):
139140
self.addCleanup(os.close, self.master_fd)
140141

141142
@unittest.skipUnless(hasattr(termios, 'TCFLSH'), 'requires termios.TCFLSH')
142-
def test_ioctl_tcflush(self):
143-
r = fcntl.ioctl(self.slave_fd, termios.TCFLSH, termios.TCIFLUSH)
144-
self.assertEqual(r, 0)
145-
r = fcntl.ioctl(self.slave_fd, termios.TCFLSH, termios.TCOFLUSH)
146-
self.assertEqual(r, 0)
143+
def test_ioctl_clear_input_or_output(self):
144+
wfd = self.slave_fd
145+
rfd = self.master_fd
146+
inbuf = sys.platform == 'linux'
147+
148+
os.write(wfd, b'abcdef')
149+
self.assertEqual(os.read(rfd, 2), b'ab')
150+
if inbuf:
151+
# don't flush input
152+
fcntl.ioctl(rfd, termios.TCFLSH, termios.TCOFLUSH)
153+
else:
154+
# don't flush output
155+
fcntl.ioctl(wfd, termios.TCFLSH, termios.TCIFLUSH)
156+
self.assertEqual(os.read(rfd, 2), b'cd')
157+
if inbuf:
158+
# flush input
159+
fcntl.ioctl(rfd, termios.TCFLSH, termios.TCIFLUSH)
160+
else:
161+
# flush output
162+
fcntl.ioctl(wfd, termios.TCFLSH, termios.TCOFLUSH)
163+
os.write(wfd, b'ABCDEF')
164+
self.assertEqual(os.read(rfd, 1024), b'ABCDEF')
165+
166+
@unittest.skipUnless(sys.platform == 'linux', 'only works on Linux')
167+
@unittest.skipUnless(hasattr(termios, 'TCXONC'), 'requires termios.TCXONC')
168+
def test_ioctl_suspend_and_resume_output(self):
169+
wfd = self.slave_fd
170+
rfd = self.master_fd
171+
write_suspended = threading.Event()
172+
write_finished = threading.Event()
173+
174+
def writer():
175+
os.write(wfd, b'abc')
176+
write_suspended.wait()
177+
os.write(wfd, b'def')
178+
write_finished.set()
179+
180+
with threading_helper.start_threads([threading.Thread(target=writer)]):
181+
self.assertEqual(os.read(rfd, 3), b'abc')
182+
try:
183+
fcntl.ioctl(wfd, termios.TCXONC, termios.TCOOFF)
184+
write_suspended.set()
185+
self.assertFalse(write_finished.wait(0.5),
186+
'output was not suspended')
187+
finally:
188+
fcntl.ioctl(wfd, termios.TCXONC, termios.TCOON)
189+
self.assertTrue(write_finished.wait(0.5),
190+
'output was not resumed')
191+
self.assertEqual(os.read(rfd, 1024), b'def')
147192

148193
def test_ioctl_set_window_size(self):
149194
# (rows, columns, xpixel, ypixel)

Lib/test/test_termios.py

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
import os
33
import sys
44
import tempfile
5+
import threading
56
import unittest
67
from test import support
8+
from test.support import threading_helper
79
from test.support.import_helper import import_module
810

911
termios = import_module('termios')
@@ -13,8 +15,8 @@
1315
class TestFunctions(unittest.TestCase):
1416

1517
def setUp(self):
16-
master_fd, self.fd = os.openpty()
17-
self.addCleanup(os.close, master_fd)
18+
self.master_fd, self.fd = os.openpty()
19+
self.addCleanup(os.close, self.master_fd)
1820
self.stream = self.enterContext(open(self.fd, 'wb', buffering=0))
1921
tmp = self.enterContext(tempfile.TemporaryFile(mode='wb', buffering=0))
2022
self.bad_fd = tmp.fileno()
@@ -147,6 +149,29 @@ def test_tcflush_errors(self):
147149
self.assertRaises(TypeError, termios.tcflush, object(), termios.TCIFLUSH)
148150
self.assertRaises(TypeError, termios.tcflush, self.fd)
149151

152+
def test_tcflush_clear_input_or_output(self):
153+
wfd = self.fd
154+
rfd = self.master_fd
155+
inbuf = sys.platform == 'linux'
156+
157+
os.write(wfd, b'abcdef')
158+
self.assertEqual(os.read(rfd, 2), b'ab')
159+
if inbuf:
160+
# don't flush input
161+
termios.tcflush(rfd, termios.TCOFLUSH)
162+
else:
163+
# don't flush output
164+
termios.tcflush(wfd, termios.TCIFLUSH)
165+
self.assertEqual(os.read(rfd, 2), b'cd')
166+
if inbuf:
167+
# flush input
168+
termios.tcflush(rfd, termios.TCIFLUSH)
169+
else:
170+
# flush output
171+
termios.tcflush(wfd, termios.TCOFLUSH)
172+
os.write(wfd, b'ABCDEF')
173+
self.assertEqual(os.read(rfd, 1024), b'ABCDEF')
174+
150175
@support.skip_android_selinux('tcflow')
151176
def test_tcflow(self):
152177
termios.tcflow(self.fd, termios.TCOOFF)
@@ -165,6 +190,32 @@ def test_tcflow_errors(self):
165190
self.assertRaises(TypeError, termios.tcflow, object(), termios.TCOON)
166191
self.assertRaises(TypeError, termios.tcflow, self.fd)
167192

193+
@unittest.skipUnless(sys.platform == 'linux', 'only works on Linux')
194+
def test_tcflow_suspend_and_resume_output(self):
195+
wfd = self.fd
196+
rfd = self.master_fd
197+
write_suspended = threading.Event()
198+
write_finished = threading.Event()
199+
200+
def writer():
201+
os.write(wfd, b'abc')
202+
write_suspended.wait()
203+
os.write(wfd, b'def')
204+
write_finished.set()
205+
206+
with threading_helper.start_threads([threading.Thread(target=writer)]):
207+
self.assertEqual(os.read(rfd, 3), b'abc')
208+
try:
209+
termios.tcflow(wfd, termios.TCOOFF)
210+
write_suspended.set()
211+
self.assertFalse(write_finished.wait(0.5),
212+
'output was not suspended')
213+
finally:
214+
termios.tcflow(wfd, termios.TCOON)
215+
self.assertTrue(write_finished.wait(0.5),
216+
'output was not resumed')
217+
self.assertEqual(os.read(rfd, 1024), b'def')
218+
168219
def test_tcgetwinsize(self):
169220
size = termios.tcgetwinsize(self.fd)
170221
self.assertIsInstance(size, tuple)

Makefile.pre.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2503,6 +2503,8 @@ maninstall: altmaninstall
25032503
XMLLIBSUBDIRS= xml xml/dom xml/etree xml/parsers xml/sax
25042504
LIBSUBDIRS= asyncio \
25052505
collections \
2506+
compression compression/bz2 compression/gzip \
2507+
compression/lzma compression/zlib compression/_common \
25062508
concurrent concurrent/futures \
25072509
csv \
25082510
ctypes ctypes/macholib \
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Many builtin and extension functions which accept an unsigned integer
2+
argument, now use :meth:`~object.__index__` if available.

Objects/longobject.c

Lines changed: 25 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1735,100 +1735,31 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow)
17351735
return res;
17361736
}
17371737

1738-
int
1739-
_PyLong_UnsignedShort_Converter(PyObject *obj, void *ptr)
1740-
{
1741-
unsigned long uval;
1742-
1743-
if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) {
1744-
PyErr_SetString(PyExc_ValueError, "value must be positive");
1745-
return 0;
1746-
}
1747-
uval = PyLong_AsUnsignedLong(obj);
1748-
if (uval == (unsigned long)-1 && PyErr_Occurred())
1749-
return 0;
1750-
if (uval > USHRT_MAX) {
1751-
PyErr_SetString(PyExc_OverflowError,
1752-
"Python int too large for C unsigned short");
1753-
return 0;
1754-
}
1755-
1756-
*(unsigned short *)ptr = Py_SAFE_DOWNCAST(uval, unsigned long, unsigned short);
1757-
return 1;
1758-
}
1759-
1760-
int
1761-
_PyLong_UnsignedInt_Converter(PyObject *obj, void *ptr)
1762-
{
1763-
unsigned long uval;
1764-
1765-
if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) {
1766-
PyErr_SetString(PyExc_ValueError, "value must be positive");
1767-
return 0;
1768-
}
1769-
uval = PyLong_AsUnsignedLong(obj);
1770-
if (uval == (unsigned long)-1 && PyErr_Occurred())
1771-
return 0;
1772-
if (uval > UINT_MAX) {
1773-
PyErr_SetString(PyExc_OverflowError,
1774-
"Python int too large for C unsigned int");
1775-
return 0;
1776-
}
1777-
1778-
*(unsigned int *)ptr = Py_SAFE_DOWNCAST(uval, unsigned long, unsigned int);
1779-
return 1;
1780-
}
1781-
1782-
int
1783-
_PyLong_UnsignedLong_Converter(PyObject *obj, void *ptr)
1784-
{
1785-
unsigned long uval;
1786-
1787-
if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) {
1788-
PyErr_SetString(PyExc_ValueError, "value must be positive");
1789-
return 0;
1790-
}
1791-
uval = PyLong_AsUnsignedLong(obj);
1792-
if (uval == (unsigned long)-1 && PyErr_Occurred())
1793-
return 0;
1794-
1795-
*(unsigned long *)ptr = uval;
1796-
return 1;
1797-
}
1798-
1799-
int
1800-
_PyLong_UnsignedLongLong_Converter(PyObject *obj, void *ptr)
1801-
{
1802-
unsigned long long uval;
1803-
1804-
if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) {
1805-
PyErr_SetString(PyExc_ValueError, "value must be positive");
1806-
return 0;
1807-
}
1808-
uval = PyLong_AsUnsignedLongLong(obj);
1809-
if (uval == (unsigned long long)-1 && PyErr_Occurred())
1810-
return 0;
1811-
1812-
*(unsigned long long *)ptr = uval;
1813-
return 1;
1814-
}
1815-
1816-
int
1817-
_PyLong_Size_t_Converter(PyObject *obj, void *ptr)
1818-
{
1819-
size_t uval;
1820-
1821-
if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) {
1822-
PyErr_SetString(PyExc_ValueError, "value must be positive");
1823-
return 0;
1824-
}
1825-
uval = PyLong_AsSize_t(obj);
1826-
if (uval == (size_t)-1 && PyErr_Occurred())
1827-
return 0;
1828-
1829-
*(size_t *)ptr = uval;
1830-
return 1;
1831-
}
1738+
#define UNSIGNED_INT_CONVERTER(NAME, TYPE) \
1739+
int \
1740+
_PyLong_##NAME##_Converter(PyObject *obj, void *ptr) \
1741+
{ \
1742+
Py_ssize_t bytes = PyLong_AsNativeBytes(obj, ptr, sizeof(TYPE), \
1743+
Py_ASNATIVEBYTES_NATIVE_ENDIAN | \
1744+
Py_ASNATIVEBYTES_ALLOW_INDEX | \
1745+
Py_ASNATIVEBYTES_REJECT_NEGATIVE | \
1746+
Py_ASNATIVEBYTES_UNSIGNED_BUFFER); \
1747+
if (bytes < 0) { \
1748+
return 0; \
1749+
} \
1750+
if ((size_t)bytes > sizeof(TYPE)) { \
1751+
PyErr_SetString(PyExc_OverflowError, \
1752+
"Python int too large for C "#TYPE); \
1753+
return 0; \
1754+
} \
1755+
return 1; \
1756+
}
1757+
1758+
UNSIGNED_INT_CONVERTER(UnsignedShort, unsigned short)
1759+
UNSIGNED_INT_CONVERTER(UnsignedInt, unsigned int)
1760+
UNSIGNED_INT_CONVERTER(UnsignedLong, unsigned long)
1761+
UNSIGNED_INT_CONVERTER(UnsignedLongLong, unsigned long long)
1762+
UNSIGNED_INT_CONVERTER(Size_t, size_t)
18321763

18331764

18341765
#define CHECK_BINOP(v,w) \

Python/traceback.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@
3333
#ifdef HAVE_LINK_H
3434
# include <link.h> // struct DL_info
3535
#endif
36-
# if defined(__APPLE__) && defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) && defined(HAVE_DLADDR)
36+
# if defined(__APPLE__) && defined(HAVE_BACKTRACE) && defined(HAVE_DLADDR)
3737
# define CAN_C_BACKTRACE
38-
# elif defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS) && defined(HAVE_DLADDR1)
38+
# elif defined(HAVE_BACKTRACE) && defined(HAVE_DLADDR1)
3939
# define CAN_C_BACKTRACE
4040
# endif
4141
#endif

0 commit comments

Comments
 (0)