Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34k
bpo-32604: Expose the subinterpreters C-API in a "private" stdlib module.#1748
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
be93a286f7a120941efdd95e734292aeaacb6e2f3ac15e79b8d809c755bb53ccad0a911395c58e0e81760eb4acc35620848e7e724f8173fb84cea3848a1a38bbdadb09a75fd2f38b1380055e809030634df53c6cb27597fb69a643dc21da6a4dad08bc818e5d80ffdbf4b8819c1b2a79406d1ec6a53db3f1e91b0e7c581a24095ab7ebae2f6d562bb237f7433b0ca21064f710703ac97e36e4d4b973cc46b9e45712efb00310d0ac8a242207c8ede947d75de153bbec79d31cd3aad28bdb728256a0c0ff9d50730b31d13091e7c8b7d2cfea73dad33ee7141c8ec513765d822e2df5aff9bb05cf633a3d374e7241bb8619ad785573f856035ba9457190650012ebc68c48291af39df95eb07e9281bfed0fFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -65,6 +65,79 @@ PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate( | ||
| PyAPI_FUNC(void) _PyPathConfig_Clear(_PyPathConfig *config); | ||
| /* interpreter state */ | ||
| PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpID(PY_INT64_T); | ||
| /* cross-interpreter data */ | ||
| struct _xid; | ||
| // _PyCrossInterpreterData is similar to Py_buffer as an effectively | ||
| // opaque struct that holds data outside the object machinery. This | ||
| // is necessary to pass between interpreters in the same process. | ||
| typedef struct _xid{ | ||
| // data is the cross-interpreter-safe derivation of a Python object | ||
| // (see _PyObject_GetCrossInterpreterData). It will be NULL if the | ||
| // new_object func (below) encodes the data. | ||
| void *data; | ||
| // obj is the Python object from which the data was derived. This | ||
| // is non-NULL only if the data remains bound to the object in some | ||
| // way, such that the object must be "released" (via a decref) when | ||
| // the data is released. In that case it is automatically | ||
| // incref'ed (to match the automatic decref when releaed). | ||
| PyObject *obj; | ||
| // interp is the ID of the owning interpreter of the original | ||
| // object. It corresponds to the active interpreter when | ||
| // _PyObject_GetCrossInterpreterData() was called. This should only | ||
| // be set by the cross-interpreter machinery. | ||
| // | ||
| // We use the ID rather than the PyInterpreterState to avoid issues | ||
| // with deleted interpreters. | ||
| int64_t interp; | ||
| // new_object is a function that returns a new object in the current | ||
| // interpreter given the data. The resulting object (a new | ||
| // reference) will be equivalent to the original object. This field | ||
| // is required. | ||
| PyObject *(*new_object)(struct _xid *); | ||
| // free is called when the data is released. If it is NULL then | ||
| // nothing will be done to free the data. For some types this is | ||
| // okay (e.g. bytes) and for those types this field should be set | ||
| // to NULL. However, for most the data was allocated just for | ||
| // cross-interpreter use, so it must be freed when | ||
| // _PyCrossInterpreterData_Release is called or the memory will | ||
| // leak. In that case, at the very least this field should be set | ||
| // to PyMem_RawFree (the default if not explicitly set to NULL). | ||
| // The call will happen with the original interpreter activated. | ||
| void (*free)(void *); | ||
| } _PyCrossInterpreterData; | ||
| ||
| typedef int (*crossinterpdatafunc)(PyObject *, _PyCrossInterpreterData *); | ||
| PyAPI_FUNC(int) _PyObject_CheckCrossInterpreterData(PyObject *); | ||
| PyAPI_FUNC(int) _PyObject_GetCrossInterpreterData(PyObject *, _PyCrossInterpreterData *); | ||
| PyAPI_FUNC(PyObject *) _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *); | ||
| PyAPI_FUNC(void) _PyCrossInterpreterData_Release(_PyCrossInterpreterData *); | ||
| /* cross-interpreter data registry */ | ||
| /* For now we use a global registry of shareable classes. An | ||
| alternative would be to add a tp_* slot for a class's | ||
| crossinterpdatafunc. It would be simpler and more efficient. */ | ||
| PyAPI_FUNC(int) _PyCrossInterpreterData_Register_Class(PyTypeObject *, crossinterpdatafunc); | ||
| PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *); | ||
| struct _xidregitem; | ||
| struct _xidregitem{ | ||
| PyTypeObject *cls; | ||
| crossinterpdatafunc getdata; | ||
| struct _xidregitem *next; | ||
| }; | ||
| /* Full Python runtime state */ | ||
| typedef struct pyruntimestate{ | ||
| @@ -86,6 +159,11 @@ typedef struct pyruntimestate{ | ||
| using a Python int. */ | ||
| int64_t next_id; | ||
| } interpreters; | ||
| // XXX Remove this field once we have a tp_* slot. | ||
| struct _xidregistry{ | ||
| PyThread_type_lock mutex; | ||
| struct _xidregitem *head; | ||
| } xidregistry; | ||
| #define NEXITFUNCS 32 | ||
| void (*exitfuncs[NEXITFUNCS])(void); | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something we'll need to keep an eye on here is not re-using interpreter IDs within the life of a process (otherwise we'll still run into issues with deleted interpreters).
Not that I've ever worked on systems where we introduced bugs by adding a freelist for objects where we assumed IDs would never be re-used or anything ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We picked int64_t so that it was both really large and would overflow to negative. When the next ID is negative PyInterpreterState_New() raises RuntimError.