bpo-31009: Move fd_count() to test.support (#7308)

* Move fd_count() from test.libregrtest.refleak to test.support
* Fix support.fd_count() on Windows: Call CrtSetReportMode() to not
  kill the process on invalid file descriptor if Python is compiled
  in debug mode.
This commit is contained in:
Victor Stinner 2018-06-01 13:47:24 +02:00 committed by GitHub
parent 1d5198fd41
commit 99ba73d118
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 39 deletions

View file

@ -13,30 +13,6 @@
MAXFD = 256
def fd_count():
"""Count the number of open file descriptors"""
if sys.platform.startswith(('linux', 'freebsd')):
try:
names = os.listdir("/proc/self/fd")
return len(names)
except FileNotFoundError:
pass
count = 0
for fd in range(MAXFD):
try:
# Prefer dup() over fstat(). fstat() can require input/output
# whereas dup() doesn't.
fd2 = os.dup(fd)
except OSError as e:
if e.errno != errno.EBADF:
raise
else:
os.close(fd2)
count += 1
return count
def dash_R(the_module, test, indirect_test, huntrleaks):
"""Run a test multiple times, looking for reference leaks.
@ -182,7 +158,7 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs):
func1 = sys.getallocatedblocks
func2 = sys.gettotalrefcount
gc.collect()
return func1(), func2(), fd_count()
return func1(), func2(), support.fd_count()
def clear_caches():

View file

@ -107,7 +107,7 @@
"check_warnings", "check_no_resource_warning", "EnvironmentVarGuard",
"run_with_locale", "swap_item",
"swap_attr", "Matcher", "set_memlimit", "SuppressCrashReport", "sortdict",
"run_with_tz", "PGO", "missing_compiler_executable",
"run_with_tz", "PGO", "missing_compiler_executable", "fd_count",
]
class Error(Exception):
@ -2691,6 +2691,63 @@ def disable_faulthandler():
faulthandler.enable(file=fd, all_threads=True)
def fd_count():
"""Count the number of open file descriptors.
"""
if sys.platform.startswith(('linux', 'freebsd')):
try:
names = os.listdir("/proc/self/fd")
return len(names)
except FileNotFoundError:
pass
old_modes = None
if sys.platform == 'win32':
# bpo-25306, bpo-31009: Call CrtSetReportMode() to not kill the process
# on invalid file descriptor if Python is compiled in debug mode
try:
import msvcrt
msvcrt.CrtSetReportMode
except (AttributeError, ImportError):
# no msvcrt or a release build
pass
else:
old_modes = {}
for report_type in (msvcrt.CRT_WARN,
msvcrt.CRT_ERROR,
msvcrt.CRT_ASSERT):
old_modes[report_type] = msvcrt.CrtSetReportMode(report_type, 0)
MAXFD = 256
if hasattr(os, 'sysconf'):
try:
MAXFD = os.sysconf("SC_OPEN_MAX")
except OSError:
pass
try:
count = 0
for fd in range(MAXFD):
try:
# Prefer dup() over fstat(). fstat() can require input/output
# whereas dup() doesn't.
fd2 = os.dup(fd)
except OSError as e:
if e.errno != errno.EBADF:
raise
else:
os.close(fd2)
count += 1
finally:
if old_modes is not None:
for report_type in (msvcrt.CRT_WARN,
msvcrt.CRT_ERROR,
msvcrt.CRT_ASSERT):
msvcrt.CrtSetReportMode(report_type, old_modes[report_type])
return count
class SaveSignals:
"""
Save an restore signal handlers.

View file

@ -835,22 +835,10 @@ def test_huntrleaks_fd_leak(self):
import os
import unittest
# Issue #25306: Disable popups and logs to stderr on assertion
# failures in MSCRT
try:
import msvcrt
msvcrt.CrtSetReportMode
except (ImportError, AttributeError):
# no Windows, o release build
pass
else:
for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
msvcrt.CrtSetReportMode(m, 0)
class FDLeakTest(unittest.TestCase):
def test_leak(self):
fd = os.open(__file__, os.O_RDONLY)
# bug: never cloes the file descriptor
# bug: never close the file descriptor
""")
self.check_leak(code, 'file descriptors')