gh-85283: Build _testconsole extension with limited C API (#117125)

This commit is contained in:
Victor Stinner 2024-03-21 17:45:43 +01:00 committed by GitHub
parent 8bea6c411d
commit abdd1f938f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 43 additions and 98 deletions

View File

@ -1527,7 +1527,7 @@ Build Changes
* The ``errno``, ``fcntl``, ``grp``, ``md5``, ``pwd``, ``resource``, * The ``errno``, ``fcntl``, ``grp``, ``md5``, ``pwd``, ``resource``,
``termios``, ``winsound``, ``termios``, ``winsound``,
``_ctypes_test``, ``_multiprocessing.posixshmem``, ``_scproxy``, ``_stat``, ``_ctypes_test``, ``_multiprocessing.posixshmem``, ``_scproxy``, ``_stat``,
``_statistics``, ``_testimportmultiple`` and ``_uuid`` ``_statistics``, ``_testconsole``, ``_testimportmultiple`` and ``_uuid``
C extensions are now built with the C extensions are now built with the
:ref:`limited C API <limited-c-api>`. :ref:`limited C API <limited-c-api>`.
(Contributed by Victor Stinner in :gh:`85283`.) (Contributed by Victor Stinner in :gh:`85283`.)

View File

@ -1,2 +1,3 @@
The ``fcntl``, ``grp``, ``pwd``, ``termios`` and ``_statistics`` C extensions are now The ``fcntl``, ``grp``, ``pwd``, ``termios``, ``_statistics`` and
built with the :ref:`limited C API <limited-c-api>`. Patch by Victor Stinner. ``_testconsole`` C extensions are now built with the :ref:`limited C API
<limited-c-api>`. Patch by Victor Stinner.

View File

@ -1,17 +1,16 @@
/* Testing module for multi-phase initialization of extension modules (PEP 489) /* Testing module for multi-phase initialization of extension modules (PEP 489)
*/ */
#ifndef Py_BUILD_CORE_BUILTIN // Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED
# define Py_BUILD_CORE_MODULE 1 #include "pyconfig.h" // Py_GIL_DISABLED
#ifndef Py_GIL_DISABLED
# define Py_LIMITED_API 0x030c0000
#endif #endif
#include "Python.h" #include "Python.h"
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
#include "pycore_fileutils.h" // _Py_get_osfhandle()
#include "pycore_runtime.h" // _Py_ID()
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <fcntl.h> #include <fcntl.h>
@ -57,20 +56,24 @@ module _testconsole
_testconsole.write_input _testconsole.write_input
file: object file: object
s: PyBytesObject s: Py_buffer
Writes UTF-16-LE encoded bytes to the console as if typed by a user. Writes UTF-16-LE encoded bytes to the console as if typed by a user.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_testconsole_write_input_impl(PyObject *module, PyObject *file, _testconsole_write_input_impl(PyObject *module, PyObject *file, Py_buffer *s)
PyBytesObject *s) /*[clinic end generated code: output=58631a8985426ad3 input=68062f1bb2e52206]*/
/*[clinic end generated code: output=48f9563db34aedb3 input=4c774f2d05770bc6]*/
{ {
INPUT_RECORD *rec = NULL; INPUT_RECORD *rec = NULL;
PyTypeObject *winconsoleio_type = (PyTypeObject *)_PyImport_GetModuleAttr( PyObject *mod = PyImport_ImportModule("_io");
&_Py_ID(_io), &_Py_ID(_WindowsConsoleIO)); if (mod == NULL) {
return NULL;
}
PyTypeObject *winconsoleio_type = (PyTypeObject *)PyObject_GetAttrString(mod, "_WindowsConsoleIO");
Py_DECREF(mod);
if (winconsoleio_type == NULL) { if (winconsoleio_type == NULL) {
return NULL; return NULL;
} }
@ -81,8 +84,8 @@ _testconsole_write_input_impl(PyObject *module, PyObject *file,
return NULL; return NULL;
} }
const wchar_t *p = (const wchar_t *)PyBytes_AS_STRING(s); const wchar_t *p = (const wchar_t *)s->buf;
DWORD size = (DWORD)PyBytes_GET_SIZE(s) / sizeof(wchar_t); DWORD size = (DWORD)s->len / sizeof(wchar_t);
rec = (INPUT_RECORD*)PyMem_Calloc(size, sizeof(INPUT_RECORD)); rec = (INPUT_RECORD*)PyMem_Calloc(size, sizeof(INPUT_RECORD));
if (!rec) if (!rec)
@ -96,9 +99,11 @@ _testconsole_write_input_impl(PyObject *module, PyObject *file,
prec->Event.KeyEvent.uChar.UnicodeChar = *p; prec->Event.KeyEvent.uChar.UnicodeChar = *p;
} }
HANDLE hInput = _Py_get_osfhandle(((winconsoleio*)file)->fd); HANDLE hInput = (HANDLE)_get_osfhandle(((winconsoleio*)file)->fd);
if (hInput == INVALID_HANDLE_VALUE) if (hInput == INVALID_HANDLE_VALUE) {
PyErr_SetFromErrno(PyExc_OSError);
goto error; goto error;
}
DWORD total = 0; DWORD total = 0;
while (total < size) { while (total < size) {

View File

@ -2,12 +2,6 @@
preserve preserve
[clinic start generated code]*/ [clinic start generated code]*/
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
# include "pycore_gc.h" // PyGC_Head
# include "pycore_runtime.h" // _Py_ID()
#endif
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
#if defined(MS_WINDOWS) #if defined(MS_WINDOWS)
PyDoc_STRVAR(_testconsole_write_input__doc__, PyDoc_STRVAR(_testconsole_write_input__doc__,
@ -17,58 +11,30 @@ PyDoc_STRVAR(_testconsole_write_input__doc__,
"Writes UTF-16-LE encoded bytes to the console as if typed by a user."); "Writes UTF-16-LE encoded bytes to the console as if typed by a user.");
#define _TESTCONSOLE_WRITE_INPUT_METHODDEF \ #define _TESTCONSOLE_WRITE_INPUT_METHODDEF \
{"write_input", _PyCFunction_CAST(_testconsole_write_input), METH_FASTCALL|METH_KEYWORDS, _testconsole_write_input__doc__}, {"write_input", (PyCFunction)(void(*)(void))_testconsole_write_input, METH_VARARGS|METH_KEYWORDS, _testconsole_write_input__doc__},
static PyObject * static PyObject *
_testconsole_write_input_impl(PyObject *module, PyObject *file, _testconsole_write_input_impl(PyObject *module, PyObject *file, Py_buffer *s);
PyBytesObject *s);
static PyObject * static PyObject *
_testconsole_write_input(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _testconsole_write_input(PyObject *module, PyObject *args, PyObject *kwargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) static char *_keywords[] = {"file", "s", NULL};
#define NUM_KEYWORDS 2
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
PyObject *ob_item[NUM_KEYWORDS];
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_item = { &_Py_ID(file), &_Py_ID(s), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
#else // !Py_BUILD_CORE
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"file", "s", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "write_input",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[2];
PyObject *file; PyObject *file;
PyBytesObject *s; Py_buffer s = {NULL, NULL};
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oy*:write_input", _keywords,
if (!args) { &file, &s))
goto exit; goto exit;
} return_value = _testconsole_write_input_impl(module, file, &s);
file = args[0];
if (!PyBytes_Check(args[1])) {
_PyArg_BadArgument("write_input", "argument 's'", "bytes", args[1]);
goto exit;
}
s = (PyBytesObject *)args[1];
return_value = _testconsole_write_input_impl(module, file, s);
exit: exit:
/* Cleanup for s */
if (s.obj) {
PyBuffer_Release(&s);
}
return return_value; return return_value;
} }
@ -83,48 +49,21 @@ PyDoc_STRVAR(_testconsole_read_output__doc__,
"Reads a str from the console as written to stdout."); "Reads a str from the console as written to stdout.");
#define _TESTCONSOLE_READ_OUTPUT_METHODDEF \ #define _TESTCONSOLE_READ_OUTPUT_METHODDEF \
{"read_output", _PyCFunction_CAST(_testconsole_read_output), METH_FASTCALL|METH_KEYWORDS, _testconsole_read_output__doc__}, {"read_output", (PyCFunction)(void(*)(void))_testconsole_read_output, METH_VARARGS|METH_KEYWORDS, _testconsole_read_output__doc__},
static PyObject * static PyObject *
_testconsole_read_output_impl(PyObject *module, PyObject *file); _testconsole_read_output_impl(PyObject *module, PyObject *file);
static PyObject * static PyObject *
_testconsole_read_output(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _testconsole_read_output(PyObject *module, PyObject *args, PyObject *kwargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) static char *_keywords[] = {"file", NULL};
#define NUM_KEYWORDS 1
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
PyObject *ob_item[NUM_KEYWORDS];
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_item = { &_Py_ID(file), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
#else // !Py_BUILD_CORE
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"file", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "read_output",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[1];
PyObject *file; PyObject *file;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:read_output", _keywords,
if (!args) { &file))
goto exit; goto exit;
}
file = args[0];
return_value = _testconsole_read_output_impl(module, file); return_value = _testconsole_read_output_impl(module, file);
exit: exit:
@ -140,4 +79,4 @@ exit:
#ifndef _TESTCONSOLE_READ_OUTPUT_METHODDEF #ifndef _TESTCONSOLE_READ_OUTPUT_METHODDEF
#define _TESTCONSOLE_READ_OUTPUT_METHODDEF #define _TESTCONSOLE_READ_OUTPUT_METHODDEF
#endif /* !defined(_TESTCONSOLE_READ_OUTPUT_METHODDEF) */ #endif /* !defined(_TESTCONSOLE_READ_OUTPUT_METHODDEF) */
/*[clinic end generated code: output=08a1c844b3657272 input=a9049054013a1b77]*/ /*[clinic end generated code: output=d60ce07157e3741a input=a9049054013a1b77]*/