LCOV - code coverage report
Current view: | top level - Modules - _xxsubinterpretersmodule.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 38 | 350 | 10.9 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 10 | 35 | 28.6 %
|  |  | Branches: | 10 | 178 | 5.6 %

               Branch data     Line data    Source code
           1                 :            :
           2                 :            : /* interpreters module */
           3                 :            : /* low-level access to interpreter primitives */
           4                 :            : #ifndef Py_BUILD_CORE_BUILTIN
           5                 :            : #  define Py_BUILD_CORE_MODULE 1
           6                 :            : #endif
           7                 :            :
           8                 :            : #include "Python.h"
           9                 :            : // XXX This module should not rely on internal API.
          10                 :            : #include "pycore_frame.h"
          11                 :            : #include "pycore_pystate.h"       // _PyThreadState_GET()
          12                 :            : #include "pycore_interpreteridobject.h"
          13                 :            :
          14                 :            :
          15                 :            : #define MODULE_NAME "_xxsubinterpreters"
          16                 :            :
          17                 :            :
          18                 :            : static const char *
          19                 :          0 : _copy_raw_string(PyObject *strobj)
          20                 :            : {
          21                 :          0 :     const char *str = PyUnicode_AsUTF8(strobj);
          22         [ #  # ]:          0 :     if (str == NULL) {
          23                 :          0 :         return NULL;
          24                 :            :     }
          25                 :          0 :     char *copied = PyMem_RawMalloc(strlen(str)+1);
          26         [ #  # ]:          0 :     if (copied == NULL) {
          27                 :          0 :         PyErr_NoMemory();
          28                 :          0 :         return NULL;
          29                 :            :     }
          30                 :          0 :     strcpy(copied, str);
          31                 :          0 :     return copied;
          32                 :            : }
          33                 :            :
          34                 :            : static PyInterpreterState *
          35                 :          0 : _get_current_interp(void)
          36                 :            : {
          37                 :            :     // PyInterpreterState_Get() aborts if lookup fails, so don't need
          38                 :            :     // to check the result for NULL.
          39                 :          0 :     return PyInterpreterState_Get();
          40                 :            : }
          41                 :            :
          42                 :            : static PyObject *
          43                 :          1 : add_new_exception(PyObject *mod, const char *name, PyObject *base)
          44                 :            : {
          45                 :            :     assert(!PyObject_HasAttrString(mod, name));
          46                 :          1 :     PyObject *exctype = PyErr_NewException(name, base, NULL);
          47         [ -  + ]:          1 :     if (exctype == NULL) {
          48                 :          0 :         return NULL;
          49                 :            :     }
          50                 :          1 :     int res = PyModule_AddType(mod, (PyTypeObject *)exctype);
          51         [ -  + ]:          1 :     if (res < 0) {
          52                 :          0 :         Py_DECREF(exctype);
          53                 :          0 :         return NULL;
          54                 :            :     }
          55                 :          1 :     return exctype;
          56                 :            : }
          57                 :            :
          58                 :            : #define ADD_NEW_EXCEPTION(MOD, NAME, BASE) \
          59                 :            :     add_new_exception(MOD, MODULE_NAME "." Py_STRINGIFY(NAME), BASE)
          60                 :            :
          61                 :            : static int
          62                 :          0 : _release_xid_data(_PyCrossInterpreterData *data, int ignoreexc)
          63                 :            : {
          64                 :            :     PyObject *exc;
          65         [ #  # ]:          0 :     if (ignoreexc) {
          66                 :          0 :         exc = PyErr_GetRaisedException();
          67                 :            :     }
          68                 :          0 :     int res = _PyCrossInterpreterData_Release(data);
          69         [ #  # ]:          0 :     if (res < 0) {
          70                 :            :         // XXX Fix this!
          71                 :            :         /* The owning interpreter is already destroyed.
          72                 :            :          * Ideally, this shouldn't ever happen.  (It's highly unlikely.)
          73                 :            :          * For now we hack around that to resolve refleaks, by decref'ing
          74                 :            :          * the released object here, even if its the wrong interpreter.
          75                 :            :          * The owning interpreter has already been destroyed
          76                 :            :          * so we should be okay, especially since the currently
          77                 :            :          * shareable types are all very basic, with no GC.
          78                 :            :          * That said, it becomes much messier once interpreters
          79                 :            :          * no longer share a GIL, so this needs to be fixed before then. */
          80                 :          0 :         _PyCrossInterpreterData_Clear(NULL, data);
          81         [ #  # ]:          0 :         if (ignoreexc) {
          82                 :            :             // XXX Emit a warning?
          83                 :          0 :             PyErr_Clear();
          84                 :            :         }
          85                 :            :     }
          86         [ #  # ]:          0 :     if (ignoreexc) {
          87                 :          0 :         PyErr_SetRaisedException(exc);
          88                 :            :     }
          89                 :          0 :     return res;
          90                 :            : }
          91                 :            :
          92                 :            :
          93                 :            : /* module state *************************************************************/
          94                 :            :
          95                 :            : typedef struct {
          96                 :            :     /* exceptions */
          97                 :            :     PyObject *RunFailedError;
          98                 :            : } module_state;
          99                 :            :
         100                 :            : static inline module_state *
         101                 :          9 : get_module_state(PyObject *mod)
         102                 :            : {
         103                 :            :     assert(mod != NULL);
         104                 :          9 :     module_state *state = PyModule_GetState(mod);
         105                 :            :     assert(state != NULL);
         106                 :          9 :     return state;
         107                 :            : }
         108                 :            :
         109                 :            : static int
         110                 :          6 : traverse_module_state(module_state *state, visitproc visit, void *arg)
         111                 :            : {
         112                 :            :     /* exceptions */
         113   [ +  -  -  + ]:          6 :     Py_VISIT(state->RunFailedError);
         114                 :            :
         115                 :          6 :     return 0;
         116                 :            : }
         117                 :            :
         118                 :            : static int
         119                 :          2 : clear_module_state(module_state *state)
         120                 :            : {
         121                 :            :     /* exceptions */
         122         [ +  + ]:          2 :     Py_CLEAR(state->RunFailedError);
         123                 :            :
         124                 :          2 :     return 0;
         125                 :            : }
         126                 :            :
         127                 :            :
         128                 :            : /* data-sharing-specific code ***********************************************/
         129                 :            :
         130                 :            : struct _sharednsitem {
         131                 :            :     const char *name;
         132                 :            :     _PyCrossInterpreterData data;
         133                 :            : };
         134                 :            :
         135                 :            : static void _sharednsitem_clear(struct _sharednsitem *);  // forward
         136                 :            :
         137                 :            : static int
         138                 :          0 : _sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
         139                 :            : {
         140                 :          0 :     item->name = _copy_raw_string(key);
         141         [ #  # ]:          0 :     if (item->name == NULL) {
         142                 :          0 :         return -1;
         143                 :            :     }
         144         [ #  # ]:          0 :     if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
         145                 :          0 :         _sharednsitem_clear(item);
         146                 :          0 :         return -1;
         147                 :            :     }
         148                 :          0 :     return 0;
         149                 :            : }
         150                 :            :
         151                 :            : static void
         152                 :          0 : _sharednsitem_clear(struct _sharednsitem *item)
         153                 :            : {
         154         [ #  # ]:          0 :     if (item->name != NULL) {
         155                 :          0 :         PyMem_RawFree((void *)item->name);
         156                 :          0 :         item->name = NULL;
         157                 :            :     }
         158                 :          0 :     (void)_release_xid_data(&item->data, 1);
         159                 :          0 : }
         160                 :            :
         161                 :            : static int
         162                 :          0 : _sharednsitem_apply(struct _sharednsitem *item, PyObject *ns)
         163                 :            : {
         164                 :          0 :     PyObject *name = PyUnicode_FromString(item->name);
         165         [ #  # ]:          0 :     if (name == NULL) {
         166                 :          0 :         return -1;
         167                 :            :     }
         168                 :          0 :     PyObject *value = _PyCrossInterpreterData_NewObject(&item->data);
         169         [ #  # ]:          0 :     if (value == NULL) {
         170                 :          0 :         Py_DECREF(name);
         171                 :          0 :         return -1;
         172                 :            :     }
         173                 :          0 :     int res = PyDict_SetItem(ns, name, value);
         174                 :          0 :     Py_DECREF(name);
         175                 :          0 :     Py_DECREF(value);
         176                 :          0 :     return res;
         177                 :            : }
         178                 :            :
         179                 :            : typedef struct _sharedns {
         180                 :            :     Py_ssize_t len;
         181                 :            :     struct _sharednsitem* items;
         182                 :            : } _sharedns;
         183                 :            :
         184                 :            : static _sharedns *
         185                 :          0 : _sharedns_new(Py_ssize_t len)
         186                 :            : {
         187                 :          0 :     _sharedns *shared = PyMem_NEW(_sharedns, 1);
         188         [ #  # ]:          0 :     if (shared == NULL) {
         189                 :          0 :         PyErr_NoMemory();
         190                 :          0 :         return NULL;
         191                 :            :     }
         192                 :          0 :     shared->len = len;
         193         [ #  # ]:          0 :     shared->items = PyMem_NEW(struct _sharednsitem, len);
         194         [ #  # ]:          0 :     if (shared->items == NULL) {
         195                 :          0 :         PyErr_NoMemory();
         196                 :          0 :         PyMem_Free(shared);
         197                 :          0 :         return NULL;
         198                 :            :     }
         199                 :          0 :     return shared;
         200                 :            : }
         201                 :            :
         202                 :            : static void
         203                 :          0 : _sharedns_free(_sharedns *shared)
         204                 :            : {
         205         [ #  # ]:          0 :     for (Py_ssize_t i=0; i < shared->len; i++) {
         206                 :          0 :         _sharednsitem_clear(&shared->items[i]);
         207                 :            :     }
         208                 :          0 :     PyMem_Free(shared->items);
         209                 :          0 :     PyMem_Free(shared);
         210                 :          0 : }
         211                 :            :
         212                 :            : static _sharedns *
         213                 :          0 : _get_shared_ns(PyObject *shareable)
         214                 :            : {
         215   [ #  #  #  # ]:          0 :     if (shareable == NULL || shareable == Py_None) {
         216                 :          0 :         return NULL;
         217                 :            :     }
         218                 :          0 :     Py_ssize_t len = PyDict_Size(shareable);
         219         [ #  # ]:          0 :     if (len == 0) {
         220                 :          0 :         return NULL;
         221                 :            :     }
         222                 :            :
         223                 :          0 :     _sharedns *shared = _sharedns_new(len);
         224         [ #  # ]:          0 :     if (shared == NULL) {
         225                 :          0 :         return NULL;
         226                 :            :     }
         227                 :          0 :     Py_ssize_t pos = 0;
         228         [ #  # ]:          0 :     for (Py_ssize_t i=0; i < len; i++) {
         229                 :            :         PyObject *key, *value;
         230         [ #  # ]:          0 :         if (PyDict_Next(shareable, &pos, &key, &value) == 0) {
         231                 :          0 :             break;
         232                 :            :         }
         233         [ #  # ]:          0 :         if (_sharednsitem_init(&shared->items[i], key, value) != 0) {
         234                 :          0 :             break;
         235                 :            :         }
         236                 :            :     }
         237         [ #  # ]:          0 :     if (PyErr_Occurred()) {
         238                 :          0 :         _sharedns_free(shared);
         239                 :          0 :         return NULL;
         240                 :            :     }
         241                 :          0 :     return shared;
         242                 :            : }
         243                 :            :
         244                 :            : static int
         245                 :          0 : _sharedns_apply(_sharedns *shared, PyObject *ns)
         246                 :            : {
         247         [ #  # ]:          0 :     for (Py_ssize_t i=0; i < shared->len; i++) {
         248         [ #  # ]:          0 :         if (_sharednsitem_apply(&shared->items[i], ns) != 0) {
         249                 :          0 :             return -1;
         250                 :            :         }
         251                 :            :     }
         252                 :          0 :     return 0;
         253                 :            : }
         254                 :            :
         255                 :            : // Ultimately we'd like to preserve enough information about the
         256                 :            : // exception and traceback that we could re-constitute (or at least
         257                 :            : // simulate, a la traceback.TracebackException), and even chain, a copy
         258                 :            : // of the exception in the calling interpreter.
         259                 :            :
         260                 :            : typedef struct _sharedexception {
         261                 :            :     const char *name;
         262                 :            :     const char *msg;
         263                 :            : } _sharedexception;
         264                 :            :
         265                 :            : static const struct _sharedexception no_exception = {
         266                 :            :     .name = NULL,
         267                 :            :     .msg = NULL,
         268                 :            : };
         269                 :            :
         270                 :            : static void
         271                 :          0 : _sharedexception_clear(_sharedexception *exc)
         272                 :            : {
         273         [ #  # ]:          0 :     if (exc->name != NULL) {
         274                 :          0 :         PyMem_RawFree((void *)exc->name);
         275                 :            :     }
         276         [ #  # ]:          0 :     if (exc->msg != NULL) {
         277                 :          0 :         PyMem_RawFree((void *)exc->msg);
         278                 :            :     }
         279                 :          0 : }
         280                 :            :
         281                 :            : static const char *
         282                 :          0 : _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
         283                 :            : {
         284                 :            :     assert(exc != NULL);
         285                 :          0 :     const char *failure = NULL;
         286                 :            :
         287                 :          0 :     PyObject *nameobj = PyUnicode_FromFormat("%S", Py_TYPE(exc));
         288         [ #  # ]:          0 :     if (nameobj == NULL) {
         289                 :          0 :         failure = "unable to format exception type name";
         290                 :          0 :         goto error;
         291                 :            :     }
         292                 :          0 :     sharedexc->name = _copy_raw_string(nameobj);
         293                 :          0 :     Py_DECREF(nameobj);
         294         [ #  # ]:          0 :     if (sharedexc->name == NULL) {
         295         [ #  # ]:          0 :         if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
         296                 :          0 :             failure = "out of memory copying exception type name";
         297                 :            :         } else {
         298                 :          0 :             failure = "unable to encode and copy exception type name";
         299                 :            :         }
         300                 :          0 :         goto error;
         301                 :            :     }
         302                 :            :
         303         [ #  # ]:          0 :     if (exc != NULL) {
         304                 :          0 :         PyObject *msgobj = PyUnicode_FromFormat("%S", exc);
         305         [ #  # ]:          0 :         if (msgobj == NULL) {
         306                 :          0 :             failure = "unable to format exception message";
         307                 :          0 :             goto error;
         308                 :            :         }
         309                 :          0 :         sharedexc->msg = _copy_raw_string(msgobj);
         310                 :          0 :         Py_DECREF(msgobj);
         311         [ #  # ]:          0 :         if (sharedexc->msg == NULL) {
         312         [ #  # ]:          0 :             if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
         313                 :          0 :                 failure = "out of memory copying exception message";
         314                 :            :             } else {
         315                 :          0 :                 failure = "unable to encode and copy exception message";
         316                 :            :             }
         317                 :          0 :             goto error;
         318                 :            :         }
         319                 :            :     }
         320                 :            :
         321                 :          0 :     return NULL;
         322                 :            :
         323                 :          0 : error:
         324                 :            :     assert(failure != NULL);
         325                 :          0 :     PyErr_Clear();
         326                 :          0 :     _sharedexception_clear(sharedexc);
         327                 :          0 :     *sharedexc = no_exception;
         328                 :          0 :     return failure;
         329                 :            : }
         330                 :            :
         331                 :            : static void
         332                 :          0 : _sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
         333                 :            : {
         334         [ #  # ]:          0 :     if (exc->name != NULL) {
         335         [ #  # ]:          0 :         if (exc->msg != NULL) {
         336                 :          0 :             PyErr_Format(wrapperclass, "%s: %s",  exc->name, exc->msg);
         337                 :            :         }
         338                 :            :         else {
         339                 :          0 :             PyErr_SetString(wrapperclass, exc->name);
         340                 :            :         }
         341                 :            :     }
         342         [ #  # ]:          0 :     else if (exc->msg != NULL) {
         343                 :          0 :         PyErr_SetString(wrapperclass, exc->msg);
         344                 :            :     }
         345                 :            :     else {
         346                 :          0 :         PyErr_SetNone(wrapperclass);
         347                 :            :     }
         348                 :          0 : }
         349                 :            :
         350                 :            :
         351                 :            : /* interpreter-specific code ************************************************/
         352                 :            :
         353                 :            : static int
         354                 :          1 : exceptions_init(PyObject *mod)
         355                 :            : {
         356                 :          1 :     module_state *state = get_module_state(mod);
         357         [ -  + ]:          1 :     if (state == NULL) {
         358                 :          0 :         return -1;
         359                 :            :     }
         360                 :            :
         361                 :            : #define ADD(NAME, BASE) \
         362                 :            :     do { \
         363                 :            :         assert(state->NAME == NULL); \
         364                 :            :         state->NAME = ADD_NEW_EXCEPTION(mod, NAME, BASE); \
         365                 :            :         if (state->NAME == NULL) { \
         366                 :            :             return -1; \
         367                 :            :         } \
         368                 :            :     } while (0)
         369                 :            :
         370                 :            :     // An uncaught exception came out of interp_run_string().
         371         [ -  + ]:          1 :     ADD(RunFailedError, PyExc_RuntimeError);
         372                 :            : #undef ADD
         373                 :            :
         374                 :          1 :     return 0;
         375                 :            : }
         376                 :            :
         377                 :            : static int
         378                 :          0 : _is_running(PyInterpreterState *interp)
         379                 :            : {
         380                 :          0 :     PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
         381         [ #  # ]:          0 :     if (PyThreadState_Next(tstate) != NULL) {
         382                 :          0 :         PyErr_SetString(PyExc_RuntimeError,
         383                 :            :                         "interpreter has more than one thread");
         384                 :          0 :         return -1;
         385                 :            :     }
         386                 :            :
         387                 :            :     assert(!PyErr_Occurred());
         388                 :          0 :     _PyInterpreterFrame *frame = tstate->cframe->current_frame;
         389         [ #  # ]:          0 :     if (frame == NULL) {
         390                 :          0 :         return 0;
         391                 :            :     }
         392                 :          0 :     return 1;
         393                 :            : }
         394                 :            :
         395                 :            : static int
         396                 :          0 : _ensure_not_running(PyInterpreterState *interp)
         397                 :            : {
         398                 :          0 :     int is_running = _is_running(interp);
         399         [ #  # ]:          0 :     if (is_running < 0) {
         400                 :          0 :         return -1;
         401                 :            :     }
         402         [ #  # ]:          0 :     if (is_running) {
         403                 :          0 :         PyErr_Format(PyExc_RuntimeError, "interpreter already running");
         404                 :          0 :         return -1;
         405                 :            :     }
         406                 :          0 :     return 0;
         407                 :            : }
         408                 :            :
         409                 :            : static int
         410                 :          0 : _run_script(PyInterpreterState *interp, const char *codestr,
         411                 :            :             _sharedns *shared, _sharedexception *sharedexc)
         412                 :            : {
         413                 :          0 :     PyObject *excval = NULL;
         414                 :          0 :     PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
         415         [ #  # ]:          0 :     if (main_mod == NULL) {
         416                 :          0 :         goto error;
         417                 :            :     }
         418                 :          0 :     PyObject *ns = PyModule_GetDict(main_mod);  // borrowed
         419                 :          0 :     Py_DECREF(main_mod);
         420         [ #  # ]:          0 :     if (ns == NULL) {
         421                 :          0 :         goto error;
         422                 :            :     }
         423                 :          0 :     Py_INCREF(ns);
         424                 :            :
         425                 :            :     // Apply the cross-interpreter data.
         426         [ #  # ]:          0 :     if (shared != NULL) {
         427         [ #  # ]:          0 :         if (_sharedns_apply(shared, ns) != 0) {
         428                 :          0 :             Py_DECREF(ns);
         429                 :          0 :             goto error;
         430                 :            :         }
         431                 :            :     }
         432                 :            :
         433                 :            :     // Run the string (see PyRun_SimpleStringFlags).
         434                 :          0 :     PyObject *result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
         435                 :          0 :     Py_DECREF(ns);
         436         [ #  # ]:          0 :     if (result == NULL) {
         437                 :          0 :         goto error;
         438                 :            :     }
         439                 :            :     else {
         440                 :          0 :         Py_DECREF(result);  // We throw away the result.
         441                 :            :     }
         442                 :            :
         443                 :          0 :     *sharedexc = no_exception;
         444                 :          0 :     return 0;
         445                 :            :
         446                 :          0 : error:
         447                 :          0 :     excval = PyErr_GetRaisedException();
         448                 :          0 :     const char *failure = _sharedexception_bind(excval, sharedexc);
         449         [ #  # ]:          0 :     if (failure != NULL) {
         450                 :          0 :         fprintf(stderr,
         451                 :            :                 "RunFailedError: script raised an uncaught exception (%s)",
         452                 :            :                 failure);
         453                 :          0 :         PyErr_Clear();
         454                 :            :     }
         455                 :          0 :     Py_XDECREF(excval);
         456                 :            :     assert(!PyErr_Occurred());
         457                 :          0 :     return -1;
         458                 :            : }
         459                 :            :
         460                 :            : static int
         461                 :          0 : _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
         462                 :            :                            const char *codestr, PyObject *shareables)
         463                 :            : {
         464         [ #  # ]:          0 :     if (_ensure_not_running(interp) < 0) {
         465                 :          0 :         return -1;
         466                 :            :     }
         467                 :          0 :     module_state *state = get_module_state(mod);
         468                 :            :
         469                 :          0 :     _sharedns *shared = _get_shared_ns(shareables);
         470   [ #  #  #  # ]:          0 :     if (shared == NULL && PyErr_Occurred()) {
         471                 :          0 :         return -1;
         472                 :            :     }
         473                 :            :
         474                 :            :     // Switch to interpreter.
         475                 :          0 :     PyThreadState *save_tstate = NULL;
         476         [ #  # ]:          0 :     if (interp != PyInterpreterState_Get()) {
         477                 :            :         // XXX Using the "head" thread isn't strictly correct.
         478                 :          0 :         PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
         479                 :            :         // XXX Possible GILState issues?
         480                 :          0 :         save_tstate = PyThreadState_Swap(tstate);
         481                 :            :     }
         482                 :            :
         483                 :            :     // Run the script.
         484                 :            :     _sharedexception exc;
         485                 :          0 :     int result = _run_script(interp, codestr, shared, &exc);
         486                 :            :
         487                 :            :     // Switch back.
         488         [ #  # ]:          0 :     if (save_tstate != NULL) {
         489                 :          0 :         PyThreadState_Swap(save_tstate);
         490                 :            :     }
         491                 :            :
         492                 :            :     // Propagate any exception out to the caller.
         493         [ #  # ]:          0 :     if (exc.name != NULL) {
         494                 :            :         assert(state != NULL);
         495                 :          0 :         _sharedexception_apply(&exc, state->RunFailedError);
         496                 :            :     }
         497         [ #  # ]:          0 :     else if (result != 0) {
         498                 :            :         // We were unable to allocate a shared exception.
         499                 :          0 :         PyErr_NoMemory();
         500                 :            :     }
         501                 :            :
         502         [ #  # ]:          0 :     if (shared != NULL) {
         503                 :          0 :         _sharedns_free(shared);
         504                 :            :     }
         505                 :            :
         506                 :          0 :     return result;
         507                 :            : }
         508                 :            :
         509                 :            :
         510                 :            : /* module level code ********************************************************/
         511                 :            :
         512                 :            : static PyObject *
         513                 :          0 : interp_create(PyObject *self, PyObject *args, PyObject *kwds)
         514                 :            : {
         515                 :            :
         516                 :            :     static char *kwlist[] = {"isolated", NULL};
         517                 :          0 :     int isolated = 1;
         518         [ #  # ]:          0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$i:create", kwlist,
         519                 :            :                                      &isolated)) {
         520                 :          0 :         return NULL;
         521                 :            :     }
         522                 :            :
         523                 :            :     // Create and initialize the new interpreter.
         524                 :          0 :     PyThreadState *save_tstate = _PyThreadState_GET();
         525                 :          0 :     const _PyInterpreterConfig config = isolated
         526         [ #  # ]:          0 :         ? (_PyInterpreterConfig)_PyInterpreterConfig_INIT
         527                 :            :         : (_PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT;
         528                 :            :     // XXX Possible GILState issues?
         529                 :          0 :     PyThreadState *tstate = _Py_NewInterpreterFromConfig(&config);
         530                 :          0 :     PyThreadState_Swap(save_tstate);
         531         [ #  # ]:          0 :     if (tstate == NULL) {
         532                 :            :         /* Since no new thread state was created, there is no exception to
         533                 :            :            propagate; raise a fresh one after swapping in the old thread
         534                 :            :            state. */
         535                 :          0 :         PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
         536                 :          0 :         return NULL;
         537                 :            :     }
         538                 :          0 :     PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate);
         539                 :          0 :     PyObject *idobj = _PyInterpreterState_GetIDObject(interp);
         540         [ #  # ]:          0 :     if (idobj == NULL) {
         541                 :            :         // XXX Possible GILState issues?
         542                 :          0 :         save_tstate = PyThreadState_Swap(tstate);
         543                 :          0 :         Py_EndInterpreter(tstate);
         544                 :          0 :         PyThreadState_Swap(save_tstate);
         545                 :          0 :         return NULL;
         546                 :            :     }
         547                 :          0 :     _PyInterpreterState_RequireIDRef(interp, 1);
         548                 :          0 :     return idobj;
         549                 :            : }
         550                 :            :
         551                 :            : PyDoc_STRVAR(create_doc,
         552                 :            : "create() -> ID\n\
         553                 :            : \n\
         554                 :            : Create a new interpreter and return a unique generated ID.");
         555                 :            :
         556                 :            :
         557                 :            : static PyObject *
         558                 :          0 : interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
         559                 :            : {
         560                 :            :     static char *kwlist[] = {"id", NULL};
         561                 :            :     PyObject *id;
         562                 :            :     // XXX Use "L" for id?
         563         [ #  # ]:          0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds,
         564                 :            :                                      "O:destroy", kwlist, &id)) {
         565                 :          0 :         return NULL;
         566                 :            :     }
         567                 :            :
         568                 :            :     // Look up the interpreter.
         569                 :          0 :     PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
         570         [ #  # ]:          0 :     if (interp == NULL) {
         571                 :          0 :         return NULL;
         572                 :            :     }
         573                 :            :
         574                 :            :     // Ensure we don't try to destroy the current interpreter.
         575                 :          0 :     PyInterpreterState *current = _get_current_interp();
         576         [ #  # ]:          0 :     if (current == NULL) {
         577                 :          0 :         return NULL;
         578                 :            :     }
         579         [ #  # ]:          0 :     if (interp == current) {
         580                 :          0 :         PyErr_SetString(PyExc_RuntimeError,
         581                 :            :                         "cannot destroy the current interpreter");
         582                 :          0 :         return NULL;
         583                 :            :     }
         584                 :            :
         585                 :            :     // Ensure the interpreter isn't running.
         586                 :            :     /* XXX We *could* support destroying a running interpreter but
         587                 :            :        aren't going to worry about it for now. */
         588         [ #  # ]:          0 :     if (_ensure_not_running(interp) < 0) {
         589                 :          0 :         return NULL;
         590                 :            :     }
         591                 :            :
         592                 :            :     // Destroy the interpreter.
         593                 :          0 :     PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
         594                 :            :     // XXX Possible GILState issues?
         595                 :          0 :     PyThreadState *save_tstate = PyThreadState_Swap(tstate);
         596                 :          0 :     Py_EndInterpreter(tstate);
         597                 :          0 :     PyThreadState_Swap(save_tstate);
         598                 :            :
         599                 :          0 :     Py_RETURN_NONE;
         600                 :            : }
         601                 :            :
         602                 :            : PyDoc_STRVAR(destroy_doc,
         603                 :            : "destroy(id)\n\
         604                 :            : \n\
         605                 :            : Destroy the identified interpreter.\n\
         606                 :            : \n\
         607                 :            : Attempting to destroy the current interpreter results in a RuntimeError.\n\
         608                 :            : So does an unrecognized ID.");
         609                 :            :
         610                 :            :
         611                 :            : static PyObject *
         612                 :          0 : interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
         613                 :            : {
         614                 :            :     PyObject *ids, *id;
         615                 :            :     PyInterpreterState *interp;
         616                 :            :
         617                 :          0 :     ids = PyList_New(0);
         618         [ #  # ]:          0 :     if (ids == NULL) {
         619                 :          0 :         return NULL;
         620                 :            :     }
         621                 :            :
         622                 :          0 :     interp = PyInterpreterState_Head();
         623         [ #  # ]:          0 :     while (interp != NULL) {
         624                 :          0 :         id = _PyInterpreterState_GetIDObject(interp);
         625         [ #  # ]:          0 :         if (id == NULL) {
         626                 :          0 :             Py_DECREF(ids);
         627                 :          0 :             return NULL;
         628                 :            :         }
         629                 :            :         // insert at front of list
         630                 :          0 :         int res = PyList_Insert(ids, 0, id);
         631                 :          0 :         Py_DECREF(id);
         632         [ #  # ]:          0 :         if (res < 0) {
         633                 :          0 :             Py_DECREF(ids);
         634                 :          0 :             return NULL;
         635                 :            :         }
         636                 :            :
         637                 :          0 :         interp = PyInterpreterState_Next(interp);
         638                 :            :     }
         639                 :            :
         640                 :          0 :     return ids;
         641                 :            : }
         642                 :            :
         643                 :            : PyDoc_STRVAR(list_all_doc,
         644                 :            : "list_all() -> [ID]\n\
         645                 :            : \n\
         646                 :            : Return a list containing the ID of every existing interpreter.");
         647                 :            :
         648                 :            :
         649                 :            : static PyObject *
         650                 :          0 : interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
         651                 :            : {
         652                 :          0 :     PyInterpreterState *interp =_get_current_interp();
         653         [ #  # ]:          0 :     if (interp == NULL) {
         654                 :          0 :         return NULL;
         655                 :            :     }
         656                 :          0 :     return _PyInterpreterState_GetIDObject(interp);
         657                 :            : }
         658                 :            :
         659                 :            : PyDoc_STRVAR(get_current_doc,
         660                 :            : "get_current() -> ID\n\
         661                 :            : \n\
         662                 :            : Return the ID of current interpreter.");
         663                 :            :
         664                 :            :
         665                 :            : static PyObject *
         666                 :          0 : interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
         667                 :            : {
         668                 :            :     // Currently, 0 is always the main interpreter.
         669                 :          0 :     int64_t id = 0;
         670                 :          0 :     return _PyInterpreterID_New(id);
         671                 :            : }
         672                 :            :
         673                 :            : PyDoc_STRVAR(get_main_doc,
         674                 :            : "get_main() -> ID\n\
         675                 :            : \n\
         676                 :            : Return the ID of main interpreter.");
         677                 :            :
         678                 :            :
         679                 :            : static PyObject *
         680                 :          0 : interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
         681                 :            : {
         682                 :            :     static char *kwlist[] = {"id", "script", "shared", NULL};
         683                 :            :     PyObject *id, *code;
         684                 :          0 :     PyObject *shared = NULL;
         685         [ #  # ]:          0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds,
         686                 :            :                                      "OU|O:run_string", kwlist,
         687                 :            :                                      &id, &code, &shared)) {
         688                 :          0 :         return NULL;
         689                 :            :     }
         690                 :            :
         691                 :            :     // Look up the interpreter.
         692                 :          0 :     PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
         693         [ #  # ]:          0 :     if (interp == NULL) {
         694                 :          0 :         return NULL;
         695                 :            :     }
         696                 :            :
         697                 :            :     // Extract code.
         698                 :            :     Py_ssize_t size;
         699                 :          0 :     const char *codestr = PyUnicode_AsUTF8AndSize(code, &size);
         700         [ #  # ]:          0 :     if (codestr == NULL) {
         701                 :          0 :         return NULL;
         702                 :            :     }
         703         [ #  # ]:          0 :     if (strlen(codestr) != (size_t)size) {
         704                 :          0 :         PyErr_SetString(PyExc_ValueError,
         705                 :            :                         "source code string cannot contain null bytes");
         706                 :          0 :         return NULL;
         707                 :            :     }
         708                 :            :
         709                 :            :     // Run the code in the interpreter.
         710         [ #  # ]:          0 :     if (_run_script_in_interpreter(self, interp, codestr, shared) != 0) {
         711                 :          0 :         return NULL;
         712                 :            :     }
         713                 :          0 :     Py_RETURN_NONE;
         714                 :            : }
         715                 :            :
         716                 :            : PyDoc_STRVAR(run_string_doc,
         717                 :            : "run_string(id, script, shared)\n\
         718                 :            : \n\
         719                 :            : Execute the provided string in the identified interpreter.\n\
         720                 :            : \n\
         721                 :            : See PyRun_SimpleStrings.");
         722                 :            :
         723                 :            :
         724                 :            : static PyObject *
         725                 :          0 : object_is_shareable(PyObject *self, PyObject *args, PyObject *kwds)
         726                 :            : {
         727                 :            :     static char *kwlist[] = {"obj", NULL};
         728                 :            :     PyObject *obj;
         729         [ #  # ]:          0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds,
         730                 :            :                                      "O:is_shareable", kwlist, &obj)) {
         731                 :          0 :         return NULL;
         732                 :            :     }
         733                 :            :
         734         [ #  # ]:          0 :     if (_PyObject_CheckCrossInterpreterData(obj) == 0) {
         735                 :          0 :         Py_RETURN_TRUE;
         736                 :            :     }
         737                 :          0 :     PyErr_Clear();
         738                 :          0 :     Py_RETURN_FALSE;
         739                 :            : }
         740                 :            :
         741                 :            : PyDoc_STRVAR(is_shareable_doc,
         742                 :            : "is_shareable(obj) -> bool\n\
         743                 :            : \n\
         744                 :            : Return True if the object's data may be shared between interpreters and\n\
         745                 :            : False otherwise.");
         746                 :            :
         747                 :            :
         748                 :            : static PyObject *
         749                 :          0 : interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
         750                 :            : {
         751                 :            :     static char *kwlist[] = {"id", NULL};
         752                 :            :     PyObject *id;
         753         [ #  # ]:          0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds,
         754                 :            :                                      "O:is_running", kwlist, &id)) {
         755                 :          0 :         return NULL;
         756                 :            :     }
         757                 :            :
         758                 :          0 :     PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
         759         [ #  # ]:          0 :     if (interp == NULL) {
         760                 :          0 :         return NULL;
         761                 :            :     }
         762                 :          0 :     int is_running = _is_running(interp);
         763         [ #  # ]:          0 :     if (is_running < 0) {
         764                 :          0 :         return NULL;
         765                 :            :     }
         766         [ #  # ]:          0 :     if (is_running) {
         767                 :          0 :         Py_RETURN_TRUE;
         768                 :            :     }
         769                 :          0 :     Py_RETURN_FALSE;
         770                 :            : }
         771                 :            :
         772                 :            : PyDoc_STRVAR(is_running_doc,
         773                 :            : "is_running(id) -> bool\n\
         774                 :            : \n\
         775                 :            : Return whether or not the identified interpreter is running.");
         776                 :            :
         777                 :            : static PyMethodDef module_functions[] = {
         778                 :            :     {"create",                    _PyCFunction_CAST(interp_create),
         779                 :            :      METH_VARARGS | METH_KEYWORDS, create_doc},
         780                 :            :     {"destroy",                   _PyCFunction_CAST(interp_destroy),
         781                 :            :      METH_VARARGS | METH_KEYWORDS, destroy_doc},
         782                 :            :     {"list_all",                  interp_list_all,
         783                 :            :      METH_NOARGS, list_all_doc},
         784                 :            :     {"get_current",               interp_get_current,
         785                 :            :      METH_NOARGS, get_current_doc},
         786                 :            :     {"get_main",                  interp_get_main,
         787                 :            :      METH_NOARGS, get_main_doc},
         788                 :            :
         789                 :            :     {"is_running",                _PyCFunction_CAST(interp_is_running),
         790                 :            :      METH_VARARGS | METH_KEYWORDS, is_running_doc},
         791                 :            :     {"run_string",                _PyCFunction_CAST(interp_run_string),
         792                 :            :      METH_VARARGS | METH_KEYWORDS, run_string_doc},
         793                 :            :
         794                 :            :     {"is_shareable",              _PyCFunction_CAST(object_is_shareable),
         795                 :            :      METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
         796                 :            :
         797                 :            :     {NULL,                        NULL}           /* sentinel */
         798                 :            : };
         799                 :            :
         800                 :            :
         801                 :            : /* initialization function */
         802                 :            :
         803                 :            : PyDoc_STRVAR(module_doc,
         804                 :            : "This module provides primitive operations to manage Python interpreters.\n\
         805                 :            : The 'interpreters' module provides a more convenient interface.");
         806                 :            :
         807                 :            : static int
         808                 :          1 : module_exec(PyObject *mod)
         809                 :            : {
         810                 :            :     /* Add exception types */
         811         [ -  + ]:          1 :     if (exceptions_init(mod) != 0) {
         812                 :          0 :         goto error;
         813                 :            :     }
         814                 :            :
         815                 :            :     // PyInterpreterID
         816         [ -  + ]:          1 :     if (PyModule_AddType(mod, &_PyInterpreterID_Type) < 0) {
         817                 :          0 :         goto error;
         818                 :            :     }
         819                 :            :
         820                 :          1 :     return 0;
         821                 :            :
         822                 :          0 : error:
         823                 :          0 :     return -1;
         824                 :            : }
         825                 :            :
         826                 :            : static struct PyModuleDef_Slot module_slots[] = {
         827                 :            :     {Py_mod_exec, module_exec},
         828                 :            :     {0, NULL},
         829                 :            : };
         830                 :            :
         831                 :            : static int
         832                 :          6 : module_traverse(PyObject *mod, visitproc visit, void *arg)
         833                 :            : {
         834                 :          6 :     module_state *state = get_module_state(mod);
         835                 :            :     assert(state != NULL);
         836                 :          6 :     traverse_module_state(state, visit, arg);
         837                 :          6 :     return 0;
         838                 :            : }
         839                 :            :
         840                 :            : static int
         841                 :          1 : module_clear(PyObject *mod)
         842                 :            : {
         843                 :          1 :     module_state *state = get_module_state(mod);
         844                 :            :     assert(state != NULL);
         845                 :          1 :     clear_module_state(state);
         846                 :          1 :     return 0;
         847                 :            : }
         848                 :            :
         849                 :            : static void
         850                 :          1 : module_free(void *mod)
         851                 :            : {
         852                 :          1 :     module_state *state = get_module_state(mod);
         853                 :            :     assert(state != NULL);
         854                 :          1 :     clear_module_state(state);
         855                 :          1 : }
         856                 :            :
         857                 :            : static struct PyModuleDef moduledef = {
         858                 :            :     .m_base = PyModuleDef_HEAD_INIT,
         859                 :            :     .m_name = MODULE_NAME,
         860                 :            :     .m_doc = module_doc,
         861                 :            :     .m_size = sizeof(module_state),
         862                 :            :     .m_methods = module_functions,
         863                 :            :     .m_slots = module_slots,
         864                 :            :     .m_traverse = module_traverse,
         865                 :            :     .m_clear = module_clear,
         866                 :            :     .m_free = (freefunc)module_free,
         867                 :            : };
         868                 :            :
         869                 :            : PyMODINIT_FUNC
         870                 :          1 : PyInit__xxsubinterpreters(void)
         871                 :            : {
         872                 :          1 :     return PyModuleDef_Init(&moduledef);
         873                 :            : }

Generated by: LCOV version 1.14