Skip to content

Commit

Permalink
Make all jep types compatible with isolated interpreters.
Browse files Browse the repository at this point in the history
* Make all jep types compatible with isolated interpreters.

* Revert pyjclass name and clean up formatting.
  • Loading branch information
bsteffensmeier authored Feb 19, 2025
1 parent 8d496d1 commit c69c642
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 258 deletions.
9 changes: 8 additions & 1 deletion src/main/c/Include/pyembed.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
jep - Java Embedded Python
Copyright (c) 2004-2022 JEP AUTHORS.
Copyright (c) 2004-2025 JEP AUTHORS.
This file is licensed under the the zlib/libpng License.
Expand Down Expand Up @@ -42,6 +42,12 @@ struct __JepThread {
};
typedef struct __JepThread JepThread;

struct __JepModuleState {
PyTypeObject *PyJObject_Type;
PyTypeObject *PyJClass_Type;
PyTypeObject *PyJArray_Type;
};
typedef struct __JepModuleState JepModuleState;

void pyembed_startup(JNIEnv*, jobjectArray, jint, jint, jstring, jint, jstring,
jint, jint, jint, jint, jint);
Expand All @@ -68,6 +74,7 @@ jobject pyembed_getvalue(JNIEnv*, intptr_t, char*, jclass);
JNIEnv* pyembed_get_env(void);
JepThread* pyembed_get_jepthread(void);
PyObject* pyembed_get_jep_module(void);
JepModuleState* pyembed_get_module_state(void);

// -------------------------------------------------- set() methods

Expand Down
4 changes: 2 additions & 2 deletions src/main/c/Include/pyjarray.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
jep - Java Embedded Python
Copyright (c) 2004-2022 JEP AUTHORS.
Copyright (c) 2004-2025 JEP AUTHORS.
This file is licensed under the the zlib/libpng License.
Expand Down Expand Up @@ -32,7 +32,7 @@
#define _Included_pyjarray


extern PyTypeObject PyJArray_Type;
extern PyType_Spec PyJArray_Spec;

// c storage for our stuff, managed by python interpreter.
typedef struct {
Expand Down
8 changes: 3 additions & 5 deletions src/main/c/Include/pyjclass.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
jep - Java Embedded Python
Copyright (c) 2004-2022 JEP AUTHORS.
Copyright (c) 2004-2025 JEP AUTHORS.
This file is licensed under the the zlib/libpng License.
Expand Down Expand Up @@ -36,7 +36,7 @@
#ifndef _Included_pyjclass
#define _Included_pyjclass

extern PyTypeObject PyJClass_Type;
extern PyType_Spec PyJClass_Spec;

typedef struct {
PyObject_HEAD
Expand All @@ -52,8 +52,6 @@ typedef struct {

PyObject* PyJClass_Wrap(JNIEnv*, jobject);

#define PyJClass_Check(pyobj) \
PyObject_TypeCheck(pyobj, &PyJClass_Type)

int PyJClass_Check(PyObject*);

#endif // ndef pyjclass
7 changes: 3 additions & 4 deletions src/main/c/Include/pyjobject.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
jep - Java Embedded Python
Copyright (c) 2004-2022 JEP AUTHORS.
Copyright (c) 2004-2025 JEP AUTHORS.
This file is licensed under the the zlib/libpng License.
Expand Down Expand Up @@ -31,7 +31,7 @@
#define _Included_pyjobject


extern PyTypeObject PyJObject_Type;
extern PyType_Spec PyJObject_Spec;

/*
* The common fields for PyJObject. The usage of this macro is similar to
Expand Down Expand Up @@ -59,8 +59,7 @@ typedef struct {
*/
PyObject* PyJObject_New(JNIEnv*, PyTypeObject*, jobject, jclass);

#define PyJObject_Check(pyobj) \
PyObject_TypeCheck(pyobj, &PyJObject_Type)
int PyJObject_Check(PyObject*);


#endif // ndef pyjobject
100 changes: 62 additions & 38 deletions src/main/c/Jep/pyembed.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
jep - Java Embedded Python
Copyright (c) 2004-2022 JEP AUTHORS.
Copyright (c) 2004-2025 JEP AUTHORS.
This file is licensed under the the zlib/libpng License.
Expand Down Expand Up @@ -157,18 +157,55 @@ static struct PyMethodDef jep_methods[] = {

{ NULL, NULL }
};

static void free_jep_module(PyObject* modjep)
{
JepModuleState* modState = (JepModuleState*) PyModule_GetState(modjep);
if (modState) {
Py_CLEAR(modState->PyJObject_Type);
Py_CLEAR(modState->PyJClass_Type);
Py_CLEAR(modState->PyJArray_Type);
}
}

static struct PyModuleDef jep_module_def = {
PyModuleDef_HEAD_INIT,
"_jep", /* m_name */
"_jep", /* m_doc */
0, /* m_size */
jep_methods, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
"_jep", /* m_name */
"_jep", /* m_doc */
sizeof(JepModuleState), /* m_size */
jep_methods, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
(freefunc) free_jep_module, /* m_free */
};

static int pyjtypes_ready(PyObject *modjep)
{
JepModuleState* modState = (JepModuleState*) PyModule_GetState(modjep);
if (!modState) {
return -1;
}
modState->PyJObject_Type = (PyTypeObject*) PyType_FromSpec(&PyJObject_Spec);
if (!modState->PyJObject_Type) {
return -1;
}
modState->PyJClass_Type = (PyTypeObject*) PyType_FromSpecWithBases(
&PyJClass_Spec, (PyObject*) modState->PyJObject_Type);
if (!modState->PyJClass_Type) {
Py_CLEAR(modState->PyJObject_Type);
return -1;
}
modState->PyJArray_Type = (PyTypeObject*) PyType_FromSpecWithBases(
&PyJArray_Spec, (PyObject*) modState->PyJObject_Type);
if (!modState->PyJArray_Type) {
Py_CLEAR(modState->PyJObject_Type);
Py_CLEAR(modState->PyJClass_Type);
return -1;
}
return 0;
}

/*
* Initialize the _jep module.
*
Expand Down Expand Up @@ -220,6 +257,12 @@ static int initjep(JNIEnv *env, jboolean hasSharedModules)
Py_INCREF(mainThreadModulesLock);
PyModule_AddObject(modjep, "mainInterpreterModulesLock", mainThreadModulesLock);
}
if (pyjtypes_ready(modjep)) {
Py_DECREF(modjep);
handle_startup_exception(env, "Failed to initialize PyJTypes");
return -1;
}

/* still held by sys.modules. */
Py_DECREF(modjep);
#if JEP_NUMPY_ENABLED
Expand All @@ -231,29 +274,6 @@ static int initjep(JNIEnv *env, jboolean hasSharedModules)
return 0;
}

/*
* MSVC requires tp_base to be set at runtime instead of in the type
* declaration. :/ Otherwise we could just set tp_base in the type declaration
* and be done with it. Since we are building an inheritance tree of types, we
* need to ensure that all the tp_base are set for the subtypes before we
* possibly use those subtypes.
*
* See https://docs.python.org/3/extending/newtypes.html
*/
static int pyjtypes_ready(void)
{
if (PyType_Ready(&PyJObject_Type) < 0) {
return -1;
}
if (!PyJClass_Type.tp_base) {
PyJClass_Type.tp_base = &PyJObject_Type;
}
if (PyType_Ready(&PyJClass_Type) < 0) {
return -1;
}
return 0;
}

static void handle_startup_exception(JNIEnv *env, const char* excMsg)
{
jclass excClass = (*env)->FindClass(env, "java/lang/IllegalStateException");
Expand Down Expand Up @@ -414,11 +434,6 @@ void pyembed_startup(JNIEnv *env,
return;
}

if (pyjtypes_ready()) {
handle_startup_exception(env, "Failed to initialize PyJTypes");
return;
}

/*
* Save a global reference to the sys.modules form the main thread to
* support shared modules
Expand Down Expand Up @@ -770,6 +785,16 @@ PyObject* pyembed_get_jep_module(void)
return modjep;
}

JepModuleState* pyembed_get_module_state(void)
{
PyObject* modjep = pyembed_get_jep_module();
if (modjep) {
return (JepModuleState*) PyModule_GetState(modjep);
} else {
return NULL;
}
}

static PyObject* pyembed_jproxy(PyObject *self, PyObject *args)
{
JepThread *jepThread;
Expand Down Expand Up @@ -1444,7 +1469,6 @@ static int maybe_pyc_file(FILE *fp, const char* filename, const char* ext,
pymodule = (PyObject *) module;



void pyembed_setparameter_object(JNIEnv *env,
intptr_t _jepThread,
intptr_t module,
Expand Down
Loading

0 comments on commit c69c642

Please sign in to comment.