-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
[C API] Hide static types from the limited C API #84781
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
"Statically allocated types" prevents to get per-interpreter GIL: bpo-40512. These types are currently shared by all interpreters. Eric Snow proposed the idea of creating a heap allocated type in subintepreters. But we should take care of direct usage of the statically allocated type. For example, Objects/longobject.c defines "PyTypeObject PyLong_Type = {...};". This type is exposed in the limited C API (!) in Include/longobject.c: PyAPI_DATA(PyTypeObject) PyLong_Type; It's used but such macro: #define PyLong_CheckExact(op) Py_IS_TYPE(op, &PyLong_Type) I don't think that these types are directly accessed in C extensions built with the limited C API. My expectation is that the type is only exposed for "CheckExact" macros. Currently, 100 statically allocated types are declared in Python header files: $ grep -F '(PyTypeObject)' Include/ -R
Include/cpython/fileobject.h:PyAPI_DATA(PyTypeObject) PyStdPrinter_Type;
(...)
Include/object.h:PyAPI_DATA(PyTypeObject) PySuper_Type; /* built-in 'super' */
Include/methodobject.h:PyAPI_DATA(PyTypeObject) PyCFunction_Type; Most of them seem to be exposed in the limited C API. I propose to break the limited C API backward compatibility on purpose by removing these type definitions form the limited C API. For "CheckExact" macros, we can continue to provide them in the limited C API but as function calls. So a built C extension would no longer access directly the type, but only do function calls. |
See also bpo-40077: "Convert static types to PyType_FromSpec()". |
Hum. How would a C extension subclass the Python int type (PyLong_Type) if it's no longer exposed? One option is to add one function per type, like: PyObject* Py_GetLongType(void); It would return a *strong reference* to the type (PyLong_Type). Another option is to get the type from builtins module or builtins dictionary (PyInterpreterState.builtins). But there is no simple C function to get a builtin object. It requires many calls, handle errors, etc. Maybe a generic helper like the following function would help: PyObject *Py_GetBuiltin(const char *name); Note: PyEval_GetBuiltins() exposes the builtins of the *current frame* which maybe not be what you may expect. Currently, Py_GetBuiltin(name) is not needed since basically *all* Python builtins are *directly* exposed in the C API... |
Technically, it is not, see https://www.python.org/dev/peps/pep-0384/#structures
That could only be done in Python 4.0, or if we started C-API 4.0. But I don't think it's necessary here. |
The symbol is exported by libpython: $ objdump -T /lib64/libpython3.8.so.1.0|grep PyLong_Type
000000000030de00 g DO .data 00000000000001a0 Base PyLong_Type A C extension can use a reference to PyLong_Type.
Did you read my rationale (first message)? Do you mean that per-interpreter GIL is not worth it? -- A first step would be to expose "CheckExact" macros as function calls in the limited C API. |
PC/python3dll.c exports 66 types in the stable ABI: Py_GenericAliasType |
Sorry, I lost this bug in my TODO list :(
Right, I mean that it it is not worth breaking the C-API for all existing modules. |
It seems that there is no continued progress for move static type in heap.This will make it impossible to continue to achieve sub interpreters parallel. Are there any plans to try other solutions to the problem? In my project, i try to slove this problem, It can work, we verify on millions of devices.
Can this change be submitted to cpython? |
The Steering Council asked for a PEP to explain why static types should be converted to heap types. |
I plan to write such PEP soon. |
FWIW I have an idea that would allow code using e.g. &PyList_Type to continue to work, and even ABI compatible (though only in the main interpreter). // In some header file PyAPI_FUNC(PyHeapTypeObject *) PyList_GetType();
#define PyList_Type (PyList_GetType()->ht_type) For the main interpreter we could make this return the address of PyList_Type. |
Sadly, I worked on other topics in the meanwhile and I left sub-interpreters aside. PEP 687 was accepted which is a step forward, even if it doesn't propose any solution for this specific problem. Until I can come up with an idea which doesn't break the API, I prefer to close the issue. If someone wants to experiment Guido's idea, please go ahead and propose a PR or even write a PEP. I'm not sure that going through #include <stdio.h>
typedef struct {
const char *name;
} PyTypeObject;
PyTypeObject PyLong_Type = {.name = "int"};
PyTypeObject* PyLong_GetType(void) {
return &PyLong_Type;
}
#define PyLong_Type_MACRO (*PyLong_GetType())
int main()
{
printf("PyLong_Type.name = %s\n", PyLong_Type.name);
// at the API level, PyLong_Type_MACRO type is a PyTypeObject instance
printf("PyLong_Type.name = %s\n", PyLong_Type_MACRO.name);
} |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: