-
Notifications
You must be signed in to change notification settings - Fork 183
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
Jpython #1176
base: master
Are you sure you want to change the base?
Jpython #1176
Changes from all commits
d2a9d06
1a97055
1e7c1a3
60b5135
25f6393
6ab676f
73ad4dd
07e8575
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,3 +85,5 @@ jacoco/ | |
wheelhouse/ | ||
vc*.pdb | ||
*.class | ||
jpython | ||
jpython.exe |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from ._core import getDefaultJVMPath | ||
import os.path | ||
|
||
_JPypeJarPath = "file://" + os.path.join(os.path.dirname(os.path.dirname(__file__)), "org.jpype.jar") | ||
_JPypeJVMPath = getDefaultJVMPath() | ||
Check notice Code scanning / CodeQL Unused global variable Note
The global variable '_JPypeJVMPath' is not used.
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -150,12 +150,10 @@ void JPContext::startJVM(const string& vmPath, const StringVector& args, | |
JP_TRACE_OUT; | ||
} | ||
|
||
void JPContext::attachJVM(JNIEnv* env) | ||
void JPContext::attachJVM(JNIEnv* env, bool embedded) | ||
{ | ||
env->GetJavaVM(&m_JavaVM); | ||
#ifndef ANDROID | ||
m_Embedded = true; | ||
#endif | ||
m_Embedded = embedded; | ||
initializeResources(env, false); | ||
} | ||
|
||
|
@@ -216,6 +214,7 @@ void JPContext::initializeResources(JNIEnv* env, bool interrupt) | |
|
||
if (!m_Embedded) | ||
{ | ||
printf("not embedded\n"); fflush(stdout); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👀 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This PR is still a work in progress. So still a lot of rough edges. I have yet to come up with a logical reason that jpype needs to be started on main thread rather than on the spawned python thread. And i need to resolve how to prevent the user from calling shutdown. That is unfortunately one of the key architectural problems with jpype. Shutdown should never have been exposed in the first place. The entry point should have spawned a thread, the original thread should have attached, then the launch thread should call destroy jvm. Modules in Python don't generally unload themselves or have time bombs to render themselves unusable, but that is what shutdown does. Unfortunately like the calling classpath from startJVM as "-Dclasspath" which should never be done(it prevents our jar from being loaded requiring sideloading with a URLClassLoader), the shutdownJVM is in all the old docs and thus ilI will forever be forced to deal with. |
||
JPPyObject import = JPPyObject::use(PyImport_AddModule("importlib.util")); | ||
JPPyObject jpype = JPPyObject::call(PyObject_CallMethod(import.get(), "find_spec", "s", "_jpype")); | ||
JPPyObject origin = JPPyObject::call(PyObject_GetAttrString(jpype.get(), "origin")); | ||
|
@@ -310,7 +309,8 @@ void JPContext::shutdownJVM(bool destroyJVM, bool freeJVM) | |
JP_TRACE_IN("JPContext::shutdown"); | ||
if (m_JavaVM == nullptr) | ||
JP_RAISE(PyExc_RuntimeError, "Attempt to shutdown without a live JVM"); | ||
// if (m_Embedded) | ||
if (m_Embedded) | ||
return; | ||
// JP_RAISE(PyExc_RuntimeError, "Cannot shutdown from embedded Python"); | ||
|
||
// Wait for all non-demon threads to terminate | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/***************************************************************************** | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
|
||
See NOTICE file for details. | ||
*****************************************************************************/ | ||
#include "jpype.h" | ||
#include "pyjp.h" | ||
|
||
void PyJPModule_installGC(PyObject* module); | ||
void PyJPModule_loadResources(PyObject* module); | ||
|
||
extern jobject urlClassLoader; | ||
|
||
extern "C" JNIEXPORT void JNICALL Java_org_jpype_Main_initialize( | ||
JNIEnv *env, jclass clazz, | ||
jobject classLoader) | ||
{ | ||
try | ||
{ | ||
// Set the classloader so that we don't make a second one during bootstrapping | ||
urlClassLoader = classLoader; | ||
// Attach the JVM | ||
JPContext_global->attachJVM(env, true); | ||
} catch (JPypeException& ex) | ||
{ | ||
printf("JPypeException\n"); | ||
} catch (...) // GCOVR_EXCL_LINE | ||
{ | ||
printf("other exception\n"); | ||
} | ||
} | ||
|
||
extern "C" JNIEXPORT void JNICALL Java_org_jpype_Main_launch( | ||
JNIEnv *env, jclass clazz, | ||
jobjectArray args) | ||
{ | ||
try { | ||
int rc = 0; | ||
// Fetch the Python modules | ||
JPPyObject publicModule = JPPyObject::use(PyImport_ImportModule("jpype")); | ||
JPPyObject privateModule = JPPyObject::use(PyImport_ImportModule("_jpype")); | ||
JPPyObject builtins = JPPyObject::use(PyEval_GetBuiltins()); | ||
if (publicModule.isNull() || privateModule.isNull() || builtins.isNull()) | ||
{ | ||
fprintf(stderr, "Unable to find required resources\n"); | ||
return; | ||
} | ||
|
||
// Set up the GC | ||
PyJPModule_installGC(privateModule.get()); | ||
PyObject_SetAttrString(builtins.get(), "jpype", publicModule.get()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The objective is to add jpype to the built-ins? 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. Like jython the goal was to have enough symbols available. Though i agree it is completely optional and i was just testing if ther was a pattern for adding to builtins. |
||
PyJPModule_loadResources(privateModule.get()); | ||
|
||
// Copy the arguments | ||
int argc = env->GetArrayLength(args); | ||
char** argv = new char*[argc]; | ||
for (int i = 0; i<argc; ++i) | ||
{ | ||
jboolean iscpy = 0; | ||
jstring str = (jstring) env->GetObjectArrayElement(args, i); | ||
const char* c = env->GetStringUTFChars(str, &iscpy); | ||
argv[i] = strdup(c); | ||
if (iscpy) | ||
env->ReleaseStringUTFChars(str, c); | ||
} | ||
|
||
// Set isolated mode so that Python doesn't call exit | ||
PyConfig config; | ||
PyConfig_InitPythonConfig(&config); | ||
config.isolated = 1; | ||
|
||
PyStatus status = PyConfig_SetBytesArgv(&config, argc, argv); | ||
if (PyStatus_Exception(status)) { | ||
PyConfig_Clear(&config); | ||
goto exception; | ||
} | ||
|
||
status = Py_InitializeFromConfig(&config); | ||
if (PyStatus_Exception(status)) { | ||
PyConfig_Clear(&config); | ||
goto exception; | ||
} | ||
PyConfig_Clear(&config); | ||
|
||
// Call Python from Java | ||
rc = Py_RunMain(); | ||
|
||
// Problem: Python doesn't exist the main loop and return here. | ||
// instead it finalizes and shutsdown everything even if there are | ||
// other Java threads still using Python. This is apparently inherent | ||
// in Python design. So it may not be possible to get them cleanly | ||
// working together until Python splits there main loop like Java | ||
// did | ||
|
||
exception: | ||
|
||
// Dump the memory | ||
for (int i = 0; i<argc; ++i) | ||
{ | ||
free(argv[i]); | ||
} | ||
|
||
// At this point there may be other threads launched by Java or Python so we | ||
// can't cleanup. Just return control. | ||
} catch (JPypeException& ex) | ||
{ | ||
JP_TRACE("JPypeException raised"); | ||
printf("JPypeException\n"); | ||
} catch (...) // GCOVR_EXCL_LINE | ||
{ | ||
printf("other exception\n"); | ||
} | ||
return; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** *************************************************************************** | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* See NOTICE file for details. | ||
**************************************************************************** */ | ||
package org.jpype; | ||
|
||
/** | ||
* | ||
* @author nelson85 | ||
*/ | ||
public class Main | ||
{ | ||
|
||
/** | ||
* Return control to Python to complete startup. | ||
* | ||
* @param args | ||
*/ | ||
static native void launch(String[] args); | ||
|
||
static native void initialize(ClassLoader loader); | ||
|
||
/** | ||
* Entry point for jpython. | ||
* | ||
* This code is only accessed from the JNI side. | ||
* | ||
* @param args | ||
*/ | ||
static void mainX(String[] args, String nativeLib) | ||
{ | ||
// Load the native library | ||
System.load(nativeLib); | ||
|
||
// Create a new main thread for Python | ||
ClassLoader classLoader = Main.class.getClassLoader(); | ||
initialize(classLoader); | ||
|
||
// Launch Python in a new thread | ||
Thread thread = new Thread(() -> launch(args), "Python"); | ||
thread.start(); | ||
// launch(args); | ||
// Return control to C so we can call Destroy and wait for shutdown. | ||
} | ||
} |
Check notice
Code scanning / CodeQL
Unused global variable Note