X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.pythonlink.win32.x86_64%2Fsrc%2Fsclpy.c;h=762df28e988aaee4b451efe8dfe5f788ccbf304e;hb=refs%2Fheads%2Frelease%2F1.34.0;hp=4881cc7d7c26d4a20979542530230724dc1df5f2;hpb=ac16ebed6a3e0932f774ca3ee5963ed776ef6c08;p=simantics%2Fpython.git diff --git a/org.simantics.pythonlink.win32.x86_64/src/sclpy.c b/org.simantics.pythonlink.win32.x86_64/src/sclpy.c index 4881cc7..762df28 100644 --- a/org.simantics.pythonlink.win32.x86_64/src/sclpy.c +++ b/org.simantics.pythonlink.win32.x86_64/src/sclpy.c @@ -32,6 +32,7 @@ jint throwIllegalArgumentException( JNIEnv *env, const char *message ) { return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message ); } +// Returns a borrowed reference. PyObject* getModule(jlong contextID) { return PyState_FindModule((PyModuleDef*) contextID); // return PyImport_AddModule("__main__"); @@ -48,50 +49,97 @@ static PyObject * writeToSCL(PyObject *self, PyObject *args) { if (currentEnv != NULL && sclWriter != NULL) { - JNIEnv *env = currentEnv; - Py_UNICODE *what; Py_ssize_t length; + JNIEnv *env = currentEnv; + if (!PyArg_ParseTuple(args, "u#", &what, &length)) - return Py_BuildValue(""); + Py_RETURN_NONE; { - jclass writerClass = (*env)->FindClass(env, WRITER_CLASS); - jmethodID writeMethod = (*env)->GetMethodID(env, writerClass, "write", "([CII)V"); - jcharArray chars = (*env)->NewCharArray(env, (jsize)length); - - (*env)->SetCharArrayRegion(env, chars, 0, length, what); - (*env)->CallVoidMethod(env, sclWriter, writeMethod, chars, 0, length); + PyThreadState *my_ts = PyThreadState_Get(); + if (my_ts == main_ts) { + jclass writerClass = (*env)->FindClass(env, WRITER_CLASS); + jmethodID writeMethod = (*env)->GetMethodID(env, writerClass, "write", "([CII)V"); + jcharArray chars = (*env)->NewCharArray(env, (jsize)length); + + (*env)->SetCharArrayRegion(env, chars, 0, length, what); + Py_BEGIN_ALLOW_THREADS + (*env)->CallVoidMethod(env, sclWriter, writeMethod, chars, 0, length); + Py_END_ALLOW_THREADS + } else { + //TODO + } } } - return Py_BuildValue(""); + Py_RETURN_NONE; +} + +static PyObject * +flushSCL(PyObject *self, PyObject *args) +{ + if (currentEnv != NULL && sclWriter != NULL) { + JNIEnv *env = currentEnv; + PyThreadState *my_ts = PyThreadState_Get(); + if (my_ts != main_ts) { + // TODO: Process calls from other threads + Py_RETURN_NONE; + } + + { + jclass writerClass = (*env)->FindClass(env, WRITER_CLASS); + jmethodID flushMethod = (*env)->GetMethodID(env, writerClass, "flush", "()V"); + + Py_BEGIN_ALLOW_THREADS + (*env)->CallVoidMethod(env, sclWriter, flushMethod); + Py_END_ALLOW_THREADS + } + } + + Py_RETURN_NONE; } static PyMethodDef sclWriterMethods[] = { {"write", writeToSCL, METH_VARARGS, "Write something."}, + {"flush", flushSCL, METH_VARARGS, "Flush output."}, {NULL, NULL, 0, NULL} }; +JNIEXPORT void JNICALL +Java_org_simantics_pythonlink_PythonContext_initializePython( + JNIEnv *env, jobject thisObj, jobject writer) { + Py_Initialize(); -JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) { - char name[16]; + { + static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods + }; + PyObject *m = PyModule_Create(&moduledef); + + sclWriter = (*env)->NewGlobalRef(env, writer); + + if (m == NULL) { + throwException(env, PYTHON_EXCEPTION, + "Failed to create SCL writer module"); + } else { + PySys_SetObject("stdout", m); + PySys_SetObject("stderr", m); + Py_DECREF(m); + } + } - if (!main_ts) { - Py_Initialize(); + hasNumpy = _import_array(); + hasNumpy = hasNumpy != -1; - { - static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods, }; - PyObject *m = PyModule_Create(&moduledef); + main_ts = PyEval_SaveThread(); +} - if (m == NULL) throwException(env, PYTHON_EXCEPTION, "Failed to create SCL writer module"); - PySys_SetObject("stdout", m); - PySys_SetObject("stderr", m); - } +JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) { + char name[16]; - hasNumpy = _import_array(); - hasNumpy = hasNumpy != -1; - main_ts = PyEval_SaveThread(); + if (!main_ts) { + return 0; } sprintf(name, "SCL_%d", ++moduleCount); @@ -106,26 +154,25 @@ JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContex modDef->m_size = -1; module = PyModule_Create(modDef); - Py_INCREF(module); PyState_AddModule(module, modDef); - { PyObject *builtin = PyImport_AddModule("builtins"); PyObject *dict = PyModule_GetDict(module); + Py_DECREF(module); PyDict_SetItemString(dict, "__builtin__", builtin); PyDict_SetItemString(dict, "__builtins__", builtin); + PyEval_SaveThread(); return (jlong)modDef; } } } -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) { +JNIEXPORT void JNICALL +Java_org_simantics_pythonlink_PythonContext_deleteContextImpl( + JNIEnv *env, jobject thisObj, jlong contextID) { PyModuleDef *modDef = (PyModuleDef*)contextID; - PyObject *module; PyEval_RestoreThread(main_ts); - module = PyState_FindModule(modDef); - Py_XDECREF(module); PyState_RemoveModule(modDef); free((char*)modDef->m_name); free(modDef); @@ -164,6 +211,7 @@ PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) { PyList_SetItem(result, i, getPythonString(env, (jstring)item)); } else { + Py_INCREF(Py_None); PyList_SetItem(result, i, Py_None); } } @@ -376,8 +424,12 @@ PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) { jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i); jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i); - PyObject *item = getPythonObject(env, componentObject, componentBinding); - PyDict_SetItem(result, getPythonString(env, fieldName), item); + PyObject + *key = getPythonString(env, fieldName), + *item = getPythonObject(env, componentObject, componentBinding); + PyDict_SetItem(result, key, item); + Py_DECREF(key); + Py_DECREF(item); } return result; @@ -400,8 +452,10 @@ PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) { jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i); if (item != NULL) PyList_SetItem(result, i, getPythonObject(env, item, componentBinding)); - else + else { + Py_INCREF(Py_None); PyList_SetItem(result, i, Py_None); + } } return result; @@ -430,7 +484,12 @@ PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) { for (i = 0; i < size; i++) { jobject key = (*env)->GetObjectArrayElement(env, keys, i); jobject item = (*env)->GetObjectArrayElement(env, values, i); - PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding)); + PyObject + *pkey = getPythonObject(env, key, keyBinding), + *pitem = getPythonObject(env, item, valueBinding); + PyDict_SetItem(result, pkey, pitem); + Py_DECREF(pkey); + Py_DECREF(pitem); } (*env)->DeleteLocalRef(env, keys); @@ -561,6 +620,7 @@ PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) { } } +// Steals refs to name & value. void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) { if (name && value) { PyDict_SetItem(PyModule_GetDict(module), name, value); @@ -650,9 +710,11 @@ jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) { PyObject *item = PySequence_GetItem(seq, i); if (PyUnicode_Check(item)) { jstring value = pythonStringAsJavaString(env, item); + Py_DECREF(item); (*env)->SetObjectArrayElement(env, array, i, value); } else { + Py_DECREF(item); throwPythonException(env, "List item not a string"); return NULL; } @@ -671,10 +733,12 @@ jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) { for (i = 0; i < jlen; i++) { PyObject *item = PySequence_GetItem(seq, i); if (PyFloat_Check(item)) { - double value = PyFloat_AsDouble(item); + jdouble value = PyFloat_AsDouble(item); + Py_DECREF(item); (*env)->SetDoubleArrayRegion(env, array, i, 1, &value); } else { + Py_DECREF(item); throwPythonException(env, "List item not a floating point value"); return NULL; } @@ -714,6 +778,7 @@ jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) { for (i = 0; i < jlen; i++) { PyObject *item = PySequence_GetItem(seq, i); jobject object = pythonObjectAsObject(env, item); + Py_DECREF(item); (*env)->SetObjectArrayElement(env, array, i, object); } @@ -731,9 +796,11 @@ jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) { PyObject *item = PySequence_GetItem(seq, i); if (PyBool_Check(item)) { jboolean value = item == Py_True; + Py_DECREF(item); (*env)->SetBooleanArrayRegion(env, array, i, 1, &value); } else { + Py_DECREF(item); throwPythonException(env, "List item not a boolean"); return NULL; } @@ -753,9 +820,11 @@ jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) { PyObject *item = PySequence_GetItem(seq, i); if (PyLong_Check(item)) { jint value = PyLong_AsLong(item); + Py_DECREF(item); (*env)->SetIntArrayRegion(env, array, i, 1, &value); } else { + Py_DECREF(item); throwPythonException(env, "List item not an integer"); return NULL; } @@ -775,9 +844,11 @@ jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) { PyObject *item = PySequence_GetItem(seq, i); if (PyLong_Check(item)) { jlong value = PyLong_AsLongLong(item); + Py_DECREF(item); (*env)->SetLongArrayRegion(env, array, i, 1, &value); } else { + Py_DECREF(item); throwPythonException(env, "List item not an integer"); return NULL; } @@ -856,9 +927,10 @@ jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) { ##VariableImpl( \ JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, \ jtype value) { \ - PyObject *module = getModule(contextID); \ + PyObject *module; \ \ PyEval_RestoreThread(main_ts); \ + module = getModule(contextID); \ setPythonVariable(module, getPythonString(env, variableName), \ j2py(env, value)); \ PyEval_SaveThread(); \ @@ -883,8 +955,6 @@ JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl( JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value) { - PyObject *module = getModule(contextID); - if (!hasNumpy) { throwPythonException(env, "Importing numpy failed"); return; @@ -892,6 +962,7 @@ Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl( PyEval_RestoreThread(main_ts); { + PyObject *module = getModule(contextID); PyObject *pythonName = getPythonString(env, variableName); PyObject *val = getPythonNDArray(env, value); @@ -904,81 +975,88 @@ JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl( JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value, jobject binding) { - PyObject *module = getModule(contextID); + PyObject *module; PyEval_RestoreThread(main_ts); + module = getModule(contextID); setPythonVariable(module, getPythonString(env, variableName), getPythonObject(env, value, binding)); PyEval_SaveThread(); } +static PyObject *getExceptionMessage(PyObject *exceptionType, PyObject *exception, PyObject *traceback) { + PyObject *formatExc = NULL, *args = NULL; + PyObject *tracebackModule = PyImport_ImportModule("traceback"); + if (!tracebackModule) { + return NULL; + } + + if (exception && traceback) { + formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception"); + args = PyTuple_Pack(3, exceptionType, exception, traceback); + } + else if (exception) { + formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception_only"); + args = PyTuple_Pack(2, exceptionType, exception); + } + + Py_DECREF(tracebackModule); + + if (formatExc != NULL && args != NULL) { + PyObject *result = PyObject_CallObject(formatExc, args); + Py_XDECREF(args); + Py_XDECREF(formatExc); + return result; + } + else { + Py_XDECREF(args); + Py_XDECREF(formatExc); + return NULL; + } +} + JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl( JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) { - PyObject *module = getModule(contextID); - const char *utfchars = (*env)->GetStringUTFChars(env, statement, NULL); PyEval_RestoreThread(main_ts); PyErr_Clear(); { - jclass sclReportingWriterClass = (*env)->FindClass(env, SCL_REPORTING_WRITER_CLASS); - jmethodID constructor = (*env)->GetMethodID(env, sclReportingWriterClass, "", "()V"); - jmethodID flushMethod = (*env)->GetMethodID(env, sclReportingWriterClass, "flush", "()V"); + PyObject *module = getModule(contextID); PyObject *globals; globals = PyModule_GetDict(module); currentEnv = env; - if (sclReportingWriterClass && constructor) - sclWriter = (*env)->NewObject(env, sclReportingWriterClass, constructor); - else - sclWriter = NULL; { PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals); - PyObject *exceptionType = PyErr_Occurred(); + if (exceptionType != NULL) { - PyObject *exception, *traceback; + PyObject *exception, *traceback, *message; PyErr_Fetch(&exceptionType, &exception, &traceback); - { - PyObject *tracebackModule = PyImport_ImportModule("traceback"); - if (tracebackModule != NULL) { - PyObject *formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception"); - if (formatExc != NULL) { - PyObject *args = PyTuple_Pack(3, exceptionType, exception, traceback); - PyObject *message = PyObject_CallObject(formatExc, args); - if (message != NULL) { - PyObject *emptyStr = PyUnicode_FromString(""); - PyObject *joined = PyUnicode_Join(emptyStr, message); - char *messageStr = PyUnicode_AsUTF8(joined); - throwPythonException(env, messageStr); - Py_DECREF(joined); - Py_DECREF(emptyStr); - Py_DECREF(message); - } - else { - PyTypeObject - *ty = (PyTypeObject *)exceptionType; - throwPythonException( - env, ty ? ty->tp_name - : "Internal error, null exception type"); - } - Py_DECREF(args); - Py_DECREF(formatExc); - } - else { - throwPythonException(env, "Internal error, no format_exc function"); - } - Py_DECREF(tracebackModule); - } - else { - throwPythonException(env, "Internal error, no traceback module"); - } + message = getExceptionMessage(exceptionType, exception, traceback); + if (message != NULL) { + PyObject *emptyStr = PyUnicode_FromString(""); + PyObject *joined = PyUnicode_Join(emptyStr, message); + char *messageStr = PyUnicode_AsUTF8(joined); + throwPythonException(env, messageStr); + Py_DECREF(joined); + Py_DECREF(emptyStr); + Py_DECREF(message); + } + else { + PyTypeObject + *ty = (PyTypeObject *)exceptionType; + throwPythonException( + env, ty ? ty->tp_name + : "Internal error, null exception type"); } + Py_XDECREF(exceptionType); Py_XDECREF(exception); Py_XDECREF(traceback); @@ -987,12 +1065,7 @@ Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl( PyEval_SaveThread(); (*env)->ReleaseStringUTFChars(env, statement, utfchars); - if (sclWriter != NULL) { - (*env)->CallVoidMethod(env, sclWriter, flushMethod); - } - currentEnv = NULL; - sclWriter = NULL; return result != NULL ? 0 : 1; } @@ -1002,7 +1075,7 @@ Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl( // Returns a borrowed reference. static PyObject *getPythonValue( JNIEnv *env, jlong contextID, jstring variableName) { - PyObject *module = getModule(contextID); + PyObject *module = getModule(contextID); PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);