From 0254493742d68e47feeaf368a9ad9f8b88b7e6f8 Mon Sep 17 00:00:00 2001 From: heck Date: Mon, 20 Apr 2020 14:06:49 +0200 Subject: [PATCH 1/4] Per object c++ mutex locking for the Engine class (java). All calls to an Engine obj are locking the mutex for their respective object. A unordered_map holds the mutex per java obj hash. The mutexes are created/deleted in constructor/destructor of an engine object. A global mutex is being locked for write operations on the unordered map (not thread safe). Cleanup of #includes --- src/basic_api.cc | 61 ++++++++++---- ...oundation_pEp_jniadapter_AbstractEngine.cc | 53 ++++++++---- src/foundation_pEp_jniadapter__Blob.cc | 5 -- src/gen_cpp_Engine.ysl2 | 9 +- src/gen_cpp_Message.ysl2 | 7 -- src/identity_api.cc | 3 - src/jniutils.cc | 55 +++++++++++-- src/jniutils.hh | 39 +++++++-- .../pEp/jniadapter/test/jni88/TestMain.java | 4 +- .../pEp/jniadapter/test/jni92/TestMain.java | 82 +++++++++++-------- 10 files changed, 217 insertions(+), 101 deletions(-) diff --git a/src/basic_api.cc b/src/basic_api.cc index 86be576..f776eab 100644 --- a/src/basic_api.cc +++ b/src/basic_api.cc @@ -1,6 +1,5 @@ #include #include -#include #include #ifndef ANDROID @@ -20,7 +19,9 @@ JNIEXPORT jbyteArray JNICALL Java_foundation_pEp_jniadapter_Engine_trustwords( jobject ident ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + pEp_identity *_ident = to_identity(env, ident); char *words; size_t wsize; @@ -58,7 +59,9 @@ JNIEXPORT jobject JNICALL Java_foundation_pEp_jniadapter_Engine_myself( jobject ident ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + pEp_identity *_ident = to_identity(env, ident); PEP_STATUS status = ::myself(session(), _ident); @@ -77,7 +80,9 @@ JNIEXPORT jobject JNICALL Java_foundation_pEp_jniadapter_Engine_updateIdentity( jobject ident ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + pEp_identity *_ident = to_identity(env, ident); ::update_identity(session(), _ident); @@ -92,7 +97,9 @@ JNIEXPORT jobject JNICALL Java_foundation_pEp_jniadapter_Engine_setOwnKey( jbyteArray fpr ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + pEp_identity *_ident = to_identity(env, ident); char *_fpr = to_string(env, fpr); @@ -113,7 +120,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_keyMistrusted( jobject ident ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + pEp_identity *_ident = to_identity(env, ident); if (_ident->fpr == NULL || _ident->fpr[0] == 0) { @@ -137,7 +146,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_keyResetTrust( jobject ident ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + pEp_identity *_ident = to_identity(env, ident); if (_ident->fpr == NULL || _ident->fpr[0] == 0) { @@ -161,7 +172,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_trustPersonalKey( jobject ident ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + pEp_identity *_ident = to_identity(env, ident); if (_ident->fpr == NULL || _ident->fpr[0] == 0) { @@ -185,7 +198,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_trustOwnKey( jobject ident ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + pEp_identity *_ident = to_identity(env, ident); if (_ident->fpr == NULL || _ident->fpr[0] == 0) { @@ -202,7 +217,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_importKey( jbyteArray key ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + size_t _size = (size_t) env->GetArrayLength(key); char *_key = (char *) env->GetByteArrayElements(key, NULL); @@ -226,7 +243,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_config_1passive_1mo jboolean enable ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + ::config_passive_mode(session(), (bool)enable); } @@ -237,7 +256,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_config_1unencrypted jboolean enable ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + ::config_unencrypted_subject(session(), (bool)enable); } @@ -247,7 +268,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_blacklist_1add( jbyteArray fpr ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + char *_fpr = to_string(env, fpr); if(_fpr == NULL){ @@ -269,7 +292,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_blacklist_1delete( jbyteArray fpr ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + char *_fpr = to_string(env, fpr); if(_fpr == NULL){ @@ -291,7 +316,9 @@ JNIEXPORT jboolean JNICALL Java_foundation_pEp_jniadapter_Engine_blacklist_1is_1 jbyteArray fpr ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + char *_fpr = to_string(env, fpr); bool _listed = 0; @@ -316,7 +343,9 @@ JNIEXPORT jbyteArray JNICALL Java_foundation_pEp_jniadapter_Engine_getCrashdumpL jint maxlines ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + int _maxlines = (int) maxlines; char *_logdata; diff --git a/src/foundation_pEp_jniadapter_AbstractEngine.cc b/src/foundation_pEp_jniadapter_AbstractEngine.cc index 51754d3..0ed33d8 100644 --- a/src/foundation_pEp_jniadapter_AbstractEngine.cc +++ b/src/foundation_pEp_jniadapter_AbstractEngine.cc @@ -1,8 +1,5 @@ #include "foundation_pEp_jniadapter_AbstractEngine.h" -#include #include -#include -#include #include #include #include @@ -28,7 +25,7 @@ jmethodID notifyHandShakeMethodID = nullptr; jmethodID needsFastPollMethodID = nullptr; jmethodID method_values = nullptr; -jobject obj = nullptr; +jobject objj = nullptr; jclass messageClass = nullptr; jclass identityClass = nullptr;; @@ -105,11 +102,11 @@ PEP_STATUS messageToSend(message *msg) pEpLog("############### messageToSend() called"); jobject msg_ = nullptr; - assert(messageClass && messageConstructorMethodID && obj && messageToSendMethodID); + assert(messageClass && messageConstructorMethodID && objj && messageToSendMethodID); msg_ = o.env()->NewObject(messageClass, messageConstructorMethodID, (jlong) msg); - PEP_STATUS status = (PEP_STATUS) o.env()->CallIntMethod(obj, messageToSendMethodID, msg_); + PEP_STATUS status = (PEP_STATUS) o.env()->CallIntMethod(objj, messageToSendMethodID, msg_); if (o.env()->ExceptionCheck()) { o.env()->ExceptionDescribe(); status = PEP_UNKNOWN_ERROR; @@ -158,9 +155,9 @@ PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, sync_handsha } } - assert(obj && notifyHandShakeMethodID); + assert(objj && notifyHandShakeMethodID); - PEP_STATUS status = (PEP_STATUS) o.env()->CallIntMethod(obj, notifyHandShakeMethodID, me_, partner_, signal_); + PEP_STATUS status = (PEP_STATUS) o.env()->CallIntMethod(objj, notifyHandShakeMethodID, me_, partner_, signal_); if (o.env()->ExceptionCheck()) { o.env()->ExceptionClear(); return PEP_UNKNOWN_ERROR; @@ -179,14 +176,18 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_init( ) { pEpLog("called"); + std::lock_guard l(global_mutex); // global mutex for write access to + if (first) { pEpLog("first Engine instance"); first = false; env->GetJavaVM(&jvm); jni_init(); - obj = env->NewGlobalRef(me); + objj = env->NewGlobalRef(me); Adapter::_messageToSend = messageToSend; } + + create_engine_java_object_mutex(env, me); // Create a mutex per java object Adapter::session(); } @@ -196,24 +197,30 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_release( ) { pEpLog("called"); + std::lock_guard l(global_mutex); // global mutex for write access to + release_engine_java_object_mutex(env, me); Adapter::session(pEp::Adapter::release); } JNIEXPORT jstring JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_getVersion( JNIEnv *env, - jobject + jobject me ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, me)); + return env->NewStringUTF(::get_engine_version()); } JNIEXPORT jstring JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_getProtocolVersion( JNIEnv *env, - jobject + jobject me ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, me)); + return env->NewStringUTF(::get_protocol_version()); } @@ -259,7 +266,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startKeyser jobject me ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, me)); + pthread_t *thread = nullptr; locked_queue< pEp_identity * > *queue = nullptr; @@ -296,7 +305,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_stopKeyserv jobject me ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, me)); + pthread_t *thread = nullptr; locked_queue< pEp_identity * > *queue = nullptr; @@ -333,7 +344,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startSync( jobject me ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, me)); + pEpLog("######## starting sync"); try { Adapter::startup(messageToSend, notifyHandshake, &o, &JNISync::onSyncStartup, &JNISync::onSyncShutdown); @@ -349,7 +362,9 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_stopSync( jobject me ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, me)); + Adapter::shutdown(); } @@ -358,7 +373,9 @@ JNIEXPORT jboolean JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_isSyncR jobject me ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, me)); + return (jboolean) Adapter::is_sync_running(); } diff --git a/src/foundation_pEp_jniadapter__Blob.cc b/src/foundation_pEp_jniadapter__Blob.cc index 9669c0a..2248708 100644 --- a/src/foundation_pEp_jniadapter__Blob.cc +++ b/src/foundation_pEp_jniadapter__Blob.cc @@ -1,11 +1,6 @@ -#include #include #include #include -#include -#include -#include - #include "jniutils.hh" #include "throw_pEp_exception.hh" #include "foundation_pEp_jniadapter__Blob.h" diff --git a/src/gen_cpp_Engine.ysl2 b/src/gen_cpp_Engine.ysl2 index 4881b7b..853d4b0 100644 --- a/src/gen_cpp_Engine.ysl2 +++ b/src/gen_cpp_Engine.ysl2 @@ -9,14 +9,11 @@ tstylesheet { template "interface" document("foundation_pEp_jniadapter_{@name}.cc", "text") || - #include - #include #include #include #include #include - #include - #include "foundation_pEp_jniadapter_«@name».h" + #include "foundation_pEp_jniadapter_Engine.h" #include "throw_pEp_exception.hh" #include "jniutils.hh" @@ -50,7 +47,9 @@ tstylesheet { jobject obj`apply "parm[in|inout]", mode=sig` ) { - pEpLog("called"); + pEpLog("called with lock_guard"); + std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + || apply "parm[in|inout]", mode=in; diff --git a/src/gen_cpp_Message.ysl2 b/src/gen_cpp_Message.ysl2 index d73497a..2d301e7 100644 --- a/src/gen_cpp_Message.ysl2 +++ b/src/gen_cpp_Message.ysl2 @@ -12,15 +12,8 @@ tstylesheet { document("foundation_pEp_jniadapter_{$jname}.cc", "text") { || - #include - #include - #include - #include - #include - #include #include #include - #include "jniutils.hh" #include "throw_pEp_exception.hh" #include "foundation_pEp_jniadapter_«$jname».h" diff --git a/src/identity_api.cc b/src/identity_api.cc index e11d4ab..feccf11 100644 --- a/src/identity_api.cc +++ b/src/identity_api.cc @@ -1,7 +1,4 @@ -#include #include -#include "jniutils.hh" - extern "C" { diff --git a/src/jniutils.cc b/src/jniutils.cc index f2d67ed..654ba8b 100644 --- a/src/jniutils.cc +++ b/src/jniutils.cc @@ -1,11 +1,5 @@ #include "jniutils.hh" -#include -#include -#include -#include -#include -#include - +#include #ifndef __LP64__ #include #define time_t time64_t @@ -17,6 +11,53 @@ namespace pEp { namespace JNIAdapter { + std::mutex global_mutex; + std::unordered_map engine_objhash_mutex; + + std::mutex* get_engine_java_object_mutex( + JNIEnv *env, + jobject obj + ) + { + int engine_obj_hash = (int)callIntMethod(env, obj, "hashCode"); + assert(engine_obj_hash); + std::mutex *engine_obj_mutex = engine_objhash_mutex.at(engine_obj_hash); + pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object hash: " << engine_obj_hash); + assert(engine_obj_mutex); + return engine_obj_mutex; + } + + void create_engine_java_object_mutex( + JNIEnv *env, + jobject obj + ) + { + int engine_obj_hash = (int)callIntMethod(env, obj, "hashCode"); + assert(engine_obj_hash); + std::mutex *engine_obj_mutex = new std::mutex(); + pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object hash: " << engine_obj_hash); + assert(engine_obj_mutex); + if(get_engine_java_object_mutex(env, obj) != nullptr ) { + pEpLog("Fatal: mutex already existing for this object"); + assert(0); + } + engine_objhash_mutex.insert(std::make_pair(engine_obj_hash, engine_obj_mutex )); + } + + void release_engine_java_object_mutex( + JNIEnv *env, + jobject obj + ) + { + int engine_obj_hash = (int)callIntMethod(env, obj, "hashCode"); + assert(engine_obj_hash); + std::mutex *engine_obj_mutex = engine_objhash_mutex.at(engine_obj_hash); + pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object hash: " << engine_obj_hash); + assert(engine_obj_mutex); + engine_objhash_mutex.erase(engine_obj_hash); + delete engine_obj_mutex; + } + jclass findClass(JNIEnv *env, const char *classname) { jclass clazz = env->FindClass(classname); diff --git a/src/jniutils.hh b/src/jniutils.hh index 88597de..57a7232 100644 --- a/src/jniutils.hh +++ b/src/jniutils.hh @@ -1,8 +1,6 @@ #pragma once - -#include -#include -#include +#include +#include #include #include #include @@ -15,11 +13,42 @@ #define LOG_TAG "pEpJNIAdapter" #define LOGD(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) #else -#define LOGD(...) +#define LOGD(...) do{}while(0) #endif namespace pEp { namespace JNIAdapter { + + // Global mutex needs to be locked in all constructors which insert their own mutex object + // into the unordered_map (which is thread safe for read, but not for write) + extern std::mutex global_mutex; + + // Stores mutex per java object + extern std::unordered_map engine_objhash_mutex; + + // needs to be called after create_engine_java_object_mutex() + // and before release_engine_java_object_mutex() + // Thread safe + std::mutex* get_engine_java_object_mutex( + JNIEnv *env, + jobject me + ); + + // Needs to be called exactly once per obj, in the constructor of the obj + // You need to lock a global mutex before calling this function (write to unordered_map) + void create_engine_java_object_mutex( + JNIEnv *env, + jobject me + ); + + // Needs to be called exactly once per obj, in the destructor of this obj + // You need to lock a global mutex before calling this function (write to unordered_map) + void release_engine_java_object_mutex( + JNIEnv *env, + jobject me + ); + + jclass findClass(JNIEnv *env, const char *classname); jfieldID getFieldID( diff --git a/test/java/foundation/pEp/jniadapter/test/jni88/TestMain.java b/test/java/foundation/pEp/jniadapter/test/jni88/TestMain.java index 4b27f39..bc53fb5 100644 --- a/test/java/foundation/pEp/jniadapter/test/jni88/TestMain.java +++ b/test/java/foundation/pEp/jniadapter/test/jni88/TestMain.java @@ -89,8 +89,8 @@ class TestThread extends Thread { class TestMain { public static void main(String[] args) { // Test parameters - boolean useSharedEngine = true; - int numThreads = 2; + boolean useSharedEngine = false; + int numThreads = 200; int numIters = 1000000000; Engine sharedEngine = null; diff --git a/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java b/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java index aaff4e9..16a020a 100644 --- a/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java +++ b/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java @@ -4,6 +4,7 @@ import foundation.pEp.jniadapter.*; import java.lang.Thread; import java.util.Vector; +import java.util.function.Consumer; /* @@ -14,13 +15,15 @@ https://pep.foundation/jira/browse/JNI-81 */ class TestThread extends Thread { - TestThread(String threadName) { + int nrEngines = 1; + TestThread(String threadName, int nrEngines) { Thread.currentThread().setName(threadName); + this.nrEngines = nrEngines; } public void run() { TestUtils.logH1( "Thread Starting"); - TestMain.TestMainRun(2); + TestMain.TestMainRun(nrEngines); } } @@ -31,7 +34,7 @@ class TestMain { Engine e; TestUtils.logH2("Creating new Engine"); e = new Engine(); - TestUtils.log("Engine created\n"); + TestUtils.log("Engine created with java object hash: " + e.hashCode()); return e; } @@ -43,51 +46,64 @@ class TestMain { return ev; } - public static void own_identities_retrieve_on_EngineVector(Vector ev) { + public static void engineConsumer(Vector ev, Consumer ec) { ev.forEach(e -> { - TestUtils.logH2("own_identities_retrieve()"); - e.own_identities_retrieve(); - TestUtils.log("\n"); + TestUtils.logH2("engineConsumer: on engine object hash: " + e.hashCode()); + ec.accept(e); }); } - public static void TestMainRun(int nrEngines) { Vector engineVector = TestMain.createEngines(nrEngines); // TestUtils.sleep(200); - TestMain.own_identities_retrieve_on_EngineVector(engineVector); + Consumer c = (e) -> { +// Vector v = e.own_identities_retrieve(); +// +// TestUtils.log("own idents: " + v.size()); +// v.forEach( i -> { +// TestUtils.log(TestUtils.identityToString(i)); +// }); + e.getVersion(); +// e.OpenPGP_list_keyinfo(""); + }; +// TestMain.engineConsumer(engineVector, c); } - public static void main(String[] args) throws Exception { + public static void main(String[] args) { TestUtils.logH1("JNI-92 Starting"); + + int nrTestruns = 1000; boolean multiThreaded = true; - int nrEngines = 3; - - if (!multiThreaded) { - // Single Threaded - TestMainRun(nrEngines); - } else { - // Mutli Threaded - Vector tts = new Vector(); - int nrThreads = nrEngines; - for (int i = 0; i < nrThreads; i++) { - tts.add(new TestThread("TestThread-" + i)); + int nrThreads = 200; + int nrEnginesPerThread = 1000; + + for (int run = 0; run < nrTestruns; run++ ) { + TestUtils.logH1("Testrun Nr: " + run); + if (!multiThreaded) { + // Single Threaded + TestMainRun(nrEnginesPerThread); + } else { + // Mutli Threaded + Vector tts = new Vector(); + for (int i = 0; i < nrThreads; i++) { + tts.add(new TestThread("TestThread-" + i, nrEnginesPerThread)); // TestUtils.sleep(200); - } + } - tts.forEach(t -> { - t.start(); + tts.forEach(t -> { + t.start(); // TestUtils.sleep(2000); - }); - - tts.forEach(t -> { - try { - t.join(); - } catch (Exception e) { - TestUtils.log("Exception joining thread" + e.toString()); - } - }); + }); + + tts.forEach(t -> { + try { + t.join(); + } catch (Exception e) { + TestUtils.log("Exception joining thread" + e.toString()); + } + }); + } } } } From d020c79c03bbb9255de311a0927cb829899b29f8 Mon Sep 17 00:00:00 2001 From: heck Date: Mon, 20 Apr 2020 15:42:54 +0200 Subject: [PATCH 2/4] Replaced hashCode() with UniquelyIdentifiable.getId() java.lang.Object.hashCode() returns non unique numbers. --- .../pEp/jniadapter/AbstractEngine.java | 2 +- .../pEp/jniadapter/UniquelyIdentifiable.java | 11 +++++++ src/jniutils.cc | 32 +++++++++---------- src/jniutils.hh | 2 +- .../pEp/jniadapter/test/jni92/TestMain.java | 14 +++++--- 5 files changed, 39 insertions(+), 22 deletions(-) create mode 100644 src/foundation/pEp/jniadapter/UniquelyIdentifiable.java diff --git a/src/foundation/pEp/jniadapter/AbstractEngine.java b/src/foundation/pEp/jniadapter/AbstractEngine.java index 0550aaa..f882fce 100644 --- a/src/foundation/pEp/jniadapter/AbstractEngine.java +++ b/src/foundation/pEp/jniadapter/AbstractEngine.java @@ -8,7 +8,7 @@ import foundation.pEp.jniadapter.Sync.DefaultCallback; import java.io.UnsupportedEncodingException; import java.text.Normalizer; -abstract class AbstractEngine implements AutoCloseable { +abstract class AbstractEngine extends UniquelyIdentifiable implements AutoCloseable { static { System.loadLibrary("pEpJNI"); } diff --git a/src/foundation/pEp/jniadapter/UniquelyIdentifiable.java b/src/foundation/pEp/jniadapter/UniquelyIdentifiable.java new file mode 100644 index 0000000..d599e9c --- /dev/null +++ b/src/foundation/pEp/jniadapter/UniquelyIdentifiable.java @@ -0,0 +1,11 @@ +package foundation.pEp.jniadapter; +import java.util.concurrent.atomic.AtomicLong; + +abstract class UniquelyIdentifiable { + static final AtomicLong NEXT_ID = new AtomicLong(1); + final long id = NEXT_ID.getAndIncrement(); + + public long getId() { + return id; + } +} diff --git a/src/jniutils.cc b/src/jniutils.cc index 654ba8b..0ca7b4d 100644 --- a/src/jniutils.cc +++ b/src/jniutils.cc @@ -12,17 +12,17 @@ namespace pEp { namespace JNIAdapter { std::mutex global_mutex; - std::unordered_map engine_objhash_mutex; + std::unordered_map engine_objid_mutex; std::mutex* get_engine_java_object_mutex( JNIEnv *env, jobject obj ) { - int engine_obj_hash = (int)callIntMethod(env, obj, "hashCode"); - assert(engine_obj_hash); - std::mutex *engine_obj_mutex = engine_objhash_mutex.at(engine_obj_hash); - pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object hash: " << engine_obj_hash); + long engine_obj_id = (long)callLongMethod(env, obj, "getId"); + assert(engine_obj_id); + std::mutex *engine_obj_mutex = engine_objid_mutex.at(engine_obj_id); + pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object id: " << engine_obj_id); assert(engine_obj_mutex); return engine_obj_mutex; } @@ -32,16 +32,16 @@ namespace pEp { jobject obj ) { - int engine_obj_hash = (int)callIntMethod(env, obj, "hashCode"); - assert(engine_obj_hash); + long engine_obj_id = (long)callLongMethod(env, obj, "getId"); + assert(engine_obj_id); std::mutex *engine_obj_mutex = new std::mutex(); - pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object hash: " << engine_obj_hash); + pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object id: " << engine_obj_id); assert(engine_obj_mutex); - if(get_engine_java_object_mutex(env, obj) != nullptr ) { - pEpLog("Fatal: mutex already existing for this object"); + if(engine_objid_mutex.count(engine_obj_id) > 0) { + pEpLog("Fatal: mutex already existing for object id: " << engine_obj_id); assert(0); } - engine_objhash_mutex.insert(std::make_pair(engine_obj_hash, engine_obj_mutex )); + engine_objid_mutex.insert(std::make_pair(engine_obj_id, engine_obj_mutex )); } void release_engine_java_object_mutex( @@ -49,12 +49,12 @@ namespace pEp { jobject obj ) { - int engine_obj_hash = (int)callIntMethod(env, obj, "hashCode"); - assert(engine_obj_hash); - std::mutex *engine_obj_mutex = engine_objhash_mutex.at(engine_obj_hash); - pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object hash: " << engine_obj_hash); + long engine_obj_id = (long)callLongMethod(env, obj, "getId"); + assert(engine_obj_id); + std::mutex *engine_obj_mutex = engine_objid_mutex.at(engine_obj_id); + pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object id: " << engine_obj_id); assert(engine_obj_mutex); - engine_objhash_mutex.erase(engine_obj_hash); + engine_objid_mutex.erase(engine_obj_id); delete engine_obj_mutex; } diff --git a/src/jniutils.hh b/src/jniutils.hh index 57a7232..a9cf9a0 100644 --- a/src/jniutils.hh +++ b/src/jniutils.hh @@ -24,7 +24,7 @@ namespace pEp { extern std::mutex global_mutex; // Stores mutex per java object - extern std::unordered_map engine_objhash_mutex; + extern std::unordered_map engine_objid_mutex; // needs to be called after create_engine_java_object_mutex() // and before release_engine_java_object_mutex() diff --git a/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java b/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java index 16a020a..000751e 100644 --- a/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java +++ b/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java @@ -34,7 +34,7 @@ class TestMain { Engine e; TestUtils.logH2("Creating new Engine"); e = new Engine(); - TestUtils.log("Engine created with java object hash: " + e.hashCode()); + TestUtils.log("Engine created with java object ID: " + e.getId()); return e; } @@ -48,7 +48,7 @@ class TestMain { public static void engineConsumer(Vector ev, Consumer ec) { ev.forEach(e -> { - TestUtils.logH2("engineConsumer: on engine object hash: " + e.hashCode()); + TestUtils.logH2("engineConsumer: on engine java object ID: " + e.getId()); ec.accept(e); }); } @@ -75,13 +75,16 @@ class TestMain { int nrTestruns = 1000; boolean multiThreaded = true; - int nrThreads = 200; + int nrThreads = 20; int nrEnginesPerThread = 1000; for (int run = 0; run < nrTestruns; run++ ) { - TestUtils.logH1("Testrun Nr: " + run); + TestUtils.logH1("Testrun Nr: " + run); if (!multiThreaded) { // Single Threaded +// for (int i = 0; i < nrEnginesPerThread; i++) { +// Engine eni = new Engine(); +// } TestMainRun(nrEnginesPerThread); } else { // Mutli Threaded @@ -104,6 +107,9 @@ class TestMain { } }); } + TestUtils.logH1("Testrun DONE" ); + System.gc(); +// TestUtils.sleep(2000); } } } From c6d2732870f78f4fc04de31d039419b7148ea938 Mon Sep 17 00:00:00 2001 From: heck Date: Mon, 20 Apr 2020 15:55:38 +0200 Subject: [PATCH 3/4] update stress test jni92 --- .../pEp/jniadapter/test/jni92/TestMain.java | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java b/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java index 000751e..a7b8cd5 100644 --- a/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java +++ b/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java @@ -29,7 +29,6 @@ class TestThread extends Thread { class TestMain { - public static Engine createNewEngine() throws pEpException { Engine e; TestUtils.logH2("Creating new Engine"); @@ -53,50 +52,43 @@ class TestMain { }); } - public static void TestMainRun(int nrEngines) { Vector engineVector = TestMain.createEngines(nrEngines); -// TestUtils.sleep(200); Consumer c = (e) -> { -// Vector v = e.own_identities_retrieve(); -// -// TestUtils.log("own idents: " + v.size()); -// v.forEach( i -> { -// TestUtils.log(TestUtils.identityToString(i)); -// }); + Vector v = e.own_identities_retrieve(); + + TestUtils.log("own idents: " + v.size()); + v.forEach( i -> { + TestUtils.log(TestUtils.identityToString(i)); + }); e.getVersion(); -// e.OpenPGP_list_keyinfo(""); + e.OpenPGP_list_keyinfo(""); }; -// TestMain.engineConsumer(engineVector, c); + TestMain.engineConsumer(engineVector, c); } public static void main(String[] args) { TestUtils.logH1("JNI-92 Starting"); - int nrTestruns = 1000; + int nrTestruns = 100; boolean multiThreaded = true; - int nrThreads = 20; - int nrEnginesPerThread = 1000; + int nrThreads = 200; + int nrEnginesPerThread = 100; for (int run = 0; run < nrTestruns; run++ ) { TestUtils.logH1("Testrun Nr: " + run); if (!multiThreaded) { // Single Threaded -// for (int i = 0; i < nrEnginesPerThread; i++) { -// Engine eni = new Engine(); -// } TestMainRun(nrEnginesPerThread); } else { // Mutli Threaded Vector tts = new Vector(); for (int i = 0; i < nrThreads; i++) { tts.add(new TestThread("TestThread-" + i, nrEnginesPerThread)); -// TestUtils.sleep(200); } tts.forEach(t -> { t.start(); -// TestUtils.sleep(2000); }); tts.forEach(t -> { From 94f2107df113982d58cda32260c8ff73c442b829 Mon Sep 17 00:00:00 2001 From: heck Date: Tue, 21 Apr 2020 00:05:12 +0200 Subject: [PATCH 4/4] Acquire global mutex to obtain mutex for java obj update stress test jni92, add option useSharedEngines --- src/basic_api.cc | 135 ++++++++++++++---- ...oundation_pEp_jniadapter_AbstractEngine.cc | 105 +++++++++----- src/gen_cpp_Engine.ysl2 | 9 +- src/jniutils.cc | 3 +- .../pEp/jniadapter/test/jni92/TestMain.java | 36 +++-- .../pEp/jniadapter/test/utils/TestUtils.java | 20 ++- 6 files changed, 226 insertions(+), 82 deletions(-) diff --git a/src/basic_api.cc b/src/basic_api.cc index f776eab..d16553b 100644 --- a/src/basic_api.cc +++ b/src/basic_api.cc @@ -19,8 +19,13 @@ JNIEXPORT jbyteArray JNICALL Java_foundation_pEp_jniadapter_Engine_trustwords( jobject ident ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); pEp_identity *_ident = to_identity(env, ident); char *words; @@ -59,8 +64,13 @@ JNIEXPORT jobject JNICALL Java_foundation_pEp_jniadapter_Engine_myself( jobject ident ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); pEp_identity *_ident = to_identity(env, ident); @@ -80,8 +90,13 @@ JNIEXPORT jobject JNICALL Java_foundation_pEp_jniadapter_Engine_updateIdentity( jobject ident ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); pEp_identity *_ident = to_identity(env, ident); @@ -97,8 +112,13 @@ JNIEXPORT jobject JNICALL Java_foundation_pEp_jniadapter_Engine_setOwnKey( jbyteArray fpr ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); pEp_identity *_ident = to_identity(env, ident); char *_fpr = to_string(env, fpr); @@ -120,8 +140,13 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_keyMistrusted( jobject ident ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); pEp_identity *_ident = to_identity(env, ident); @@ -146,8 +171,13 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_keyResetTrust( jobject ident ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); pEp_identity *_ident = to_identity(env, ident); @@ -172,8 +202,13 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_trustPersonalKey( jobject ident ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); pEp_identity *_ident = to_identity(env, ident); @@ -198,8 +233,13 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_trustOwnKey( jobject ident ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); pEp_identity *_ident = to_identity(env, ident); @@ -217,8 +257,13 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_importKey( jbyteArray key ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); size_t _size = (size_t) env->GetArrayLength(key); char *_key = (char *) env->GetByteArrayElements(key, NULL); @@ -243,8 +288,13 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_config_1passive_1mo jboolean enable ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); ::config_passive_mode(session(), (bool)enable); } @@ -256,8 +306,13 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_config_1unencrypted jboolean enable ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); ::config_unencrypted_subject(session(), (bool)enable); } @@ -268,8 +323,13 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_blacklist_1add( jbyteArray fpr ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); char *_fpr = to_string(env, fpr); @@ -292,8 +352,13 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_blacklist_1delete( jbyteArray fpr ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); char *_fpr = to_string(env, fpr); @@ -316,8 +381,13 @@ JNIEXPORT jboolean JNICALL Java_foundation_pEp_jniadapter_Engine_blacklist_1is_1 jbyteArray fpr ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); char *_fpr = to_string(env, fpr); bool _listed = 0; @@ -343,8 +413,13 @@ JNIEXPORT jbyteArray JNICALL Java_foundation_pEp_jniadapter_Engine_getCrashdumpL jint maxlines ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); int _maxlines = (int) maxlines; char *_logdata; diff --git a/src/foundation_pEp_jniadapter_AbstractEngine.cc b/src/foundation_pEp_jniadapter_AbstractEngine.cc index 0ed33d8..40d4e03 100644 --- a/src/foundation_pEp_jniadapter_AbstractEngine.cc +++ b/src/foundation_pEp_jniadapter_AbstractEngine.cc @@ -172,54 +172,64 @@ using namespace pEp; JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_init( JNIEnv *env, - jobject me + jobject obj ) { - pEpLog("called"); std::lock_guard l(global_mutex); // global mutex for write access to + pEpLog("called"); if (first) { pEpLog("first Engine instance"); first = false; env->GetJavaVM(&jvm); jni_init(); - objj = env->NewGlobalRef(me); + objj = env->NewGlobalRef(obj); Adapter::_messageToSend = messageToSend; } - create_engine_java_object_mutex(env, me); // Create a mutex per java object + create_engine_java_object_mutex(env, obj); // Create a mutex per java object Adapter::session(); } JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_release( JNIEnv *env, - jobject me + jobject obj ) { - pEpLog("called"); std::lock_guard l(global_mutex); // global mutex for write access to - release_engine_java_object_mutex(env, me); + pEpLog("called"); + release_engine_java_object_mutex(env, obj); Adapter::session(pEp::Adapter::release); } JNIEXPORT jstring JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_getVersion( JNIEnv *env, - jobject me + jobject obj ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, me)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); return env->NewStringUTF(::get_engine_version()); } JNIEXPORT jstring JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_getProtocolVersion( JNIEnv *env, - jobject me + jobject obj ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, me)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); return env->NewStringUTF(::get_protocol_version()); } @@ -263,11 +273,16 @@ static void *keyserver_thread_routine(void *arg) JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startKeyserverLookup( JNIEnv *env, - jobject me + jobject obj ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, me)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); pthread_t *thread = nullptr; locked_queue< pEp_identity * > *queue = nullptr; @@ -284,16 +299,16 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startKeyser return; } - thread = (pthread_t *) env->GetLongField(me, thread_handle); + thread = (pthread_t *) env->GetLongField(obj, thread_handle); if (thread) return; thread = (pthread_t *) calloc(1, sizeof(pthread_t)); assert(thread); - env->SetLongField(me, thread_handle, (jlong) thread); + env->SetLongField(obj, thread_handle, (jlong) thread); queue = new locked_queue< pEp_identity * >(); - env->SetLongField(me, queue_handle, (jlong) queue); + env->SetLongField(obj, queue_handle, (jlong) queue); register_examine_function(Adapter::session(), examine_identity, (void *) queue); @@ -302,11 +317,16 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startKeyser JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_stopKeyserverLookup( JNIEnv *env, - jobject me + jobject obj ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, me)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); pthread_t *thread = nullptr; locked_queue< pEp_identity * > *queue = nullptr; @@ -323,14 +343,14 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_stopKeyserv return; } - thread = (pthread_t *) env->GetLongField(me, thread_handle); + thread = (pthread_t *) env->GetLongField(obj, thread_handle); if (!thread) return; - queue = (locked_queue< pEp_identity * > *) env->GetLongField(me, queue_handle); + queue = (locked_queue< pEp_identity * > *) env->GetLongField(obj, queue_handle); - env->SetLongField(me, queue_handle, (jlong) 0); - env->SetLongField(me, thread_handle, (jlong) 0); + env->SetLongField(obj, queue_handle, (jlong) 0); + env->SetLongField(obj, thread_handle, (jlong) 0); register_examine_function(Adapter::session(), nullptr, nullptr); @@ -341,11 +361,16 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_stopKeyserv JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startSync( JNIEnv *env, - jobject me + jobject obj ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, me)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); pEpLog("######## starting sync"); try { @@ -359,22 +384,32 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startSync( JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_stopSync( JNIEnv *env, - jobject me + jobject obj ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, me)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); Adapter::shutdown(); } JNIEXPORT jboolean JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_isSyncRunning( JNIEnv *env, - jobject me + jobject obj ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, me)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); return (jboolean) Adapter::is_sync_running(); } diff --git a/src/gen_cpp_Engine.ysl2 b/src/gen_cpp_Engine.ysl2 index 853d4b0..3fb0e1c 100644 --- a/src/gen_cpp_Engine.ysl2 +++ b/src/gen_cpp_Engine.ysl2 @@ -47,8 +47,13 @@ tstylesheet { jobject obj`apply "parm[in|inout]", mode=sig` ) { - pEpLog("called with lock_guard"); - std::lock_guard l(*get_engine_java_object_mutex(env, obj)); + std::mutex *mutex_local = nullptr; + { + std::lock_guard l(global_mutex); + pEpLog("called with lock_guard"); + mutex_local = get_engine_java_object_mutex(env, obj); + } + std::lock_guard l(*mutex_local); || diff --git a/src/jniutils.cc b/src/jniutils.cc index 0ca7b4d..e4d2820 100644 --- a/src/jniutils.cc +++ b/src/jniutils.cc @@ -21,8 +21,9 @@ namespace pEp { { long engine_obj_id = (long)callLongMethod(env, obj, "getId"); assert(engine_obj_id); + pEpLog("for java object id: " << engine_obj_id); std::mutex *engine_obj_mutex = engine_objid_mutex.at(engine_obj_id); - pEpLog(engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle() << " for java object id: " << engine_obj_id); + pEpLog("found mutex: " << engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle()); assert(engine_obj_mutex); return engine_obj_mutex; } diff --git a/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java b/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java index a7b8cd5..a646590 100644 --- a/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java +++ b/test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java @@ -16,19 +16,23 @@ https://pep.foundation/jira/browse/JNI-81 class TestThread extends Thread { int nrEngines = 1; - TestThread(String threadName, int nrEngines) { + boolean useSharedEngines = false; + TestThread(String threadName, int nrEngines, boolean useSharedEngines) { Thread.currentThread().setName(threadName); this.nrEngines = nrEngines; + this.useSharedEngines = useSharedEngines; } public void run() { TestUtils.logH1( "Thread Starting"); - TestMain.TestMainRun(nrEngines); + TestMain.TestMainRun(nrEngines, useSharedEngines); } } class TestMain { + static Vector sharedEngines; + public static Engine createNewEngine() throws pEpException { Engine e; TestUtils.logH2("Creating new Engine"); @@ -52,8 +56,7 @@ class TestMain { }); } - public static void TestMainRun(int nrEngines) { - Vector engineVector = TestMain.createEngines(nrEngines); + public static void TestMainRun(int nrEngines, boolean useSharedEngines) { Consumer c = (e) -> { Vector v = e.own_identities_retrieve(); @@ -64,27 +67,38 @@ class TestMain { e.getVersion(); e.OpenPGP_list_keyinfo(""); }; - TestMain.engineConsumer(engineVector, c); + + if(useSharedEngines) { + TestMain.engineConsumer(sharedEngines, c); + } else { + Vector threadLocalEngines = TestMain.createEngines(nrEngines); + TestMain.engineConsumer(threadLocalEngines, c); + } } public static void main(String[] args) { TestUtils.logH1("JNI-92 Starting"); - - int nrTestruns = 100; + TestUtils.setLoggingEnabled(false); + int nrTestruns = 1000; boolean multiThreaded = true; - int nrThreads = 200; - int nrEnginesPerThread = 100; + boolean useSharedEngines = true; + int nrThreads = 100; + int nrEnginesPerThread = 1; + + if(useSharedEngines) { + sharedEngines = TestMain.createEngines(nrEnginesPerThread); + } for (int run = 0; run < nrTestruns; run++ ) { TestUtils.logH1("Testrun Nr: " + run); if (!multiThreaded) { // Single Threaded - TestMainRun(nrEnginesPerThread); + TestMainRun(nrEnginesPerThread, useSharedEngines); } else { // Mutli Threaded Vector tts = new Vector(); for (int i = 0; i < nrThreads; i++) { - tts.add(new TestThread("TestThread-" + i, nrEnginesPerThread)); + tts.add(new TestThread("TestThread-" + i, nrEnginesPerThread, useSharedEngines)); } tts.forEach(t -> { diff --git a/test/java/foundation/pEp/jniadapter/test/utils/TestUtils.java b/test/java/foundation/pEp/jniadapter/test/utils/TestUtils.java index 83d7d75..3833b18 100644 --- a/test/java/foundation/pEp/jniadapter/test/utils/TestUtils.java +++ b/test/java/foundation/pEp/jniadapter/test/utils/TestUtils.java @@ -22,10 +22,24 @@ public class TestUtils { return ret; } + // ------------------------ Logging ------------------------ + + private static boolean logEnabled = true; + + public static void setLoggingEnabled(boolean enabled) { + logEnabled = enabled; + } + + public static boolean isLoggingEnabled() { + return logEnabled; + } + public static void log(String msg) { - String threadNameFmt = String.format("%-10s", Thread.currentThread().getName()); - String msgOut = threadNameFmt + ": " + msg; - System.out.println(msgOut); + if(logEnabled) { + String threadNameFmt = String.format("%-10s", Thread.currentThread().getName()); + String msgOut = threadNameFmt + ": " + msg; + System.out.println(msgOut); + } } public static void logH1(String msg) {