Browse Source

Reintegrate feature branch JNI-92 - Mutex Locking Per Engine Instance

(yes, you are right, there will be undefined behaviour after 9.2 sextillion engine instances)
sync
heck 5 years ago
parent
commit
81a8887ab6
  1. 136
      src/basic_api.cc
  2. 2
      src/foundation/pEp/jniadapter/AbstractEngine.java
  3. 11
      src/foundation/pEp/jniadapter/UniquelyIdentifiable.java
  4. 119
      src/foundation_pEp_jniadapter_AbstractEngine.cc
  5. 5
      src/foundation_pEp_jniadapter__Blob.cc
  6. 11
      src/gen_cpp_Engine.ysl2
  7. 7
      src/gen_cpp_Message.ysl2
  8. 3
      src/identity_api.cc
  9. 56
      src/jniutils.cc
  10. 39
      src/jniutils.hh
  11. 4
      test/java/foundation/pEp/jniadapter/test/jni88/TestMain.java
  12. 98
      test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java
  13. 20
      test/java/foundation/pEp/jniadapter/test/utils/TestUtils.java

136
src/basic_api.cc

@ -1,6 +1,5 @@
#include <pEp/keymanagement.h> #include <pEp/keymanagement.h>
#include <pEp/blacklist.h> #include <pEp/blacklist.h>
#include <pEp/sync_api.h>
#include <pEp/Adapter.hh> #include <pEp/Adapter.hh>
#ifndef ANDROID #ifndef ANDROID
@ -20,7 +19,14 @@ JNIEXPORT jbyteArray JNICALL Java_foundation_pEp_jniadapter_Engine_trustwords(
jobject ident jobject ident
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
pEp_identity *_ident = to_identity(env, ident); pEp_identity *_ident = to_identity(env, ident);
char *words; char *words;
size_t wsize; size_t wsize;
@ -58,7 +64,14 @@ JNIEXPORT jobject JNICALL Java_foundation_pEp_jniadapter_Engine_myself(
jobject ident jobject ident
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
pEp_identity *_ident = to_identity(env, ident); pEp_identity *_ident = to_identity(env, ident);
PEP_STATUS status = ::myself(session(), _ident); PEP_STATUS status = ::myself(session(), _ident);
@ -77,7 +90,14 @@ JNIEXPORT jobject JNICALL Java_foundation_pEp_jniadapter_Engine_updateIdentity(
jobject ident jobject ident
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
pEp_identity *_ident = to_identity(env, ident); pEp_identity *_ident = to_identity(env, ident);
::update_identity(session(), _ident); ::update_identity(session(), _ident);
@ -92,7 +112,14 @@ JNIEXPORT jobject JNICALL Java_foundation_pEp_jniadapter_Engine_setOwnKey(
jbyteArray fpr jbyteArray fpr
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
pEp_identity *_ident = to_identity(env, ident); pEp_identity *_ident = to_identity(env, ident);
char *_fpr = to_string(env, fpr); char *_fpr = to_string(env, fpr);
@ -113,7 +140,14 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_keyMistrusted(
jobject ident jobject ident
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
pEp_identity *_ident = to_identity(env, ident); pEp_identity *_ident = to_identity(env, ident);
if (_ident->fpr == NULL || _ident->fpr[0] == 0) { if (_ident->fpr == NULL || _ident->fpr[0] == 0) {
@ -137,7 +171,14 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_keyResetTrust(
jobject ident jobject ident
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
pEp_identity *_ident = to_identity(env, ident); pEp_identity *_ident = to_identity(env, ident);
if (_ident->fpr == NULL || _ident->fpr[0] == 0) { if (_ident->fpr == NULL || _ident->fpr[0] == 0) {
@ -161,7 +202,14 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_trustPersonalKey(
jobject ident jobject ident
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
pEp_identity *_ident = to_identity(env, ident); pEp_identity *_ident = to_identity(env, ident);
if (_ident->fpr == NULL || _ident->fpr[0] == 0) { if (_ident->fpr == NULL || _ident->fpr[0] == 0) {
@ -185,7 +233,14 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_trustOwnKey(
jobject ident jobject ident
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
pEp_identity *_ident = to_identity(env, ident); pEp_identity *_ident = to_identity(env, ident);
if (_ident->fpr == NULL || _ident->fpr[0] == 0) { if (_ident->fpr == NULL || _ident->fpr[0] == 0) {
@ -202,7 +257,14 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_importKey(
jbyteArray key jbyteArray key
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
size_t _size = (size_t) env->GetArrayLength(key); size_t _size = (size_t) env->GetArrayLength(key);
char *_key = (char *) env->GetByteArrayElements(key, NULL); char *_key = (char *) env->GetByteArrayElements(key, NULL);
@ -226,7 +288,14 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_config_1passive_1mo
jboolean enable jboolean enable
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
::config_passive_mode(session(), (bool)enable); ::config_passive_mode(session(), (bool)enable);
} }
@ -237,7 +306,14 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_config_1unencrypted
jboolean enable jboolean enable
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
::config_unencrypted_subject(session(), (bool)enable); ::config_unencrypted_subject(session(), (bool)enable);
} }
@ -247,7 +323,14 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_blacklist_1add(
jbyteArray fpr jbyteArray fpr
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
char *_fpr = to_string(env, fpr); char *_fpr = to_string(env, fpr);
if(_fpr == NULL){ if(_fpr == NULL){
@ -269,7 +352,14 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_Engine_blacklist_1delete(
jbyteArray fpr jbyteArray fpr
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
char *_fpr = to_string(env, fpr); char *_fpr = to_string(env, fpr);
if(_fpr == NULL){ if(_fpr == NULL){
@ -291,7 +381,14 @@ JNIEXPORT jboolean JNICALL Java_foundation_pEp_jniadapter_Engine_blacklist_1is_1
jbyteArray fpr jbyteArray fpr
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
char *_fpr = to_string(env, fpr); char *_fpr = to_string(env, fpr);
bool _listed = 0; bool _listed = 0;
@ -316,7 +413,14 @@ JNIEXPORT jbyteArray JNICALL Java_foundation_pEp_jniadapter_Engine_getCrashdumpL
jint maxlines jint maxlines
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
int _maxlines = (int) maxlines; int _maxlines = (int) maxlines;
char *_logdata; char *_logdata;

2
src/foundation/pEp/jniadapter/AbstractEngine.java

@ -8,7 +8,7 @@ import foundation.pEp.jniadapter.Sync.DefaultCallback;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.text.Normalizer; import java.text.Normalizer;
abstract class AbstractEngine implements AutoCloseable { abstract class AbstractEngine extends UniquelyIdentifiable implements AutoCloseable {
static { static {
System.loadLibrary("pEpJNI"); System.loadLibrary("pEpJNI");
} }

11
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;
}
}

119
src/foundation_pEp_jniadapter_AbstractEngine.cc

@ -1,8 +1,5 @@
#include "foundation_pEp_jniadapter_AbstractEngine.h" #include "foundation_pEp_jniadapter_AbstractEngine.h"
#include <stdexcept>
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#include <pthread.h>
#include <pEp/keymanagement.h> #include <pEp/keymanagement.h>
#include <pEp/message_api.h> #include <pEp/message_api.h>
#include <pEp/sync_api.h> #include <pEp/sync_api.h>
@ -28,7 +25,7 @@ jmethodID notifyHandShakeMethodID = nullptr;
jmethodID needsFastPollMethodID = nullptr; jmethodID needsFastPollMethodID = nullptr;
jmethodID method_values = nullptr; jmethodID method_values = nullptr;
jobject obj = nullptr; jobject objj = nullptr;
jclass messageClass = nullptr; jclass messageClass = nullptr;
jclass identityClass = nullptr;; jclass identityClass = nullptr;;
@ -96,15 +93,15 @@ void jni_init() {
PEP_STATUS messageToSend(message *msg) PEP_STATUS messageToSend(message *msg)
{ {
std::lock_guard<std::mutex> l(mutex_obj); std::lock_guard<std::mutex> l(mutex_obj);
pEpLog("############### messageToSend() called");
pEpLog("############### messageToSend() called");
jobject msg_ = nullptr; jobject msg_ = nullptr;
assert(messageClass && messageConstructorMethodID && obj && messageToSendMethodID); assert(messageClass && messageConstructorMethodID && objj && messageToSendMethodID);
msg_ = o.env()->NewObject(messageClass, messageConstructorMethodID, (jlong) msg); 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()) { if (o.env()->ExceptionCheck()) {
o.env()->ExceptionDescribe(); o.env()->ExceptionDescribe();
status = PEP_UNKNOWN_ERROR; status = PEP_UNKNOWN_ERROR;
@ -118,8 +115,8 @@ PEP_STATUS messageToSend(message *msg)
PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal) PEP_STATUS notifyHandshake(pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal)
{ {
std::lock_guard<std::mutex> l(mutex_obj); std::lock_guard<std::mutex> l(mutex_obj);
pEpLog("############### notifyHandshake() called");
pEpLog("############### notifyHandshake() called");
jobject me_ = nullptr; jobject me_ = nullptr;
jobject partner_ = nullptr; jobject partner_ = nullptr;
@ -152,9 +149,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()) { if (o.env()->ExceptionCheck()) {
o.env()->ExceptionClear(); o.env()->ExceptionClear();
return PEP_UNKNOWN_ERROR; return PEP_UNKNOWN_ERROR;
@ -169,45 +166,65 @@ using namespace pEp;
JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_init( JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_init(
JNIEnv *env, JNIEnv *env,
jobject me jobject obj
) )
{ {
std::lock_guard<std::mutex> l(global_mutex); // global mutex for write access to <unordered_map>
pEpLog("called"); pEpLog("called");
if (first) { if (first) {
pEpLog("first Engine instance"); pEpLog("first Engine instance");
first = false; first = false;
env->GetJavaVM(&jvm); env->GetJavaVM(&jvm);
jni_init(); jni_init();
obj = env->NewGlobalRef(me); objj = env->NewGlobalRef(obj);
Adapter::_messageToSend = messageToSend; Adapter::_messageToSend = messageToSend;
} }
create_engine_java_object_mutex(env, obj); // Create a mutex per java object
Adapter::session(); Adapter::session();
} }
JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_release( JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_release(
JNIEnv *env, JNIEnv *env,
jobject me jobject obj
) )
{ {
std::lock_guard<std::mutex> l(global_mutex); // global mutex for write access to <unordered_map>
pEpLog("called"); pEpLog("called");
release_engine_java_object_mutex(env, obj);
Adapter::session(pEp::Adapter::release); Adapter::session(pEp::Adapter::release);
} }
JNIEXPORT jstring JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_getVersion( JNIEXPORT jstring JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_getVersion(
JNIEnv *env, JNIEnv *env,
jobject jobject obj
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
return env->NewStringUTF(::get_engine_version()); return env->NewStringUTF(::get_engine_version());
} }
JNIEXPORT jstring JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_getProtocolVersion( JNIEXPORT jstring JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_getProtocolVersion(
JNIEnv *env, JNIEnv *env,
jobject jobject obj
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
return env->NewStringUTF(::get_protocol_version()); return env->NewStringUTF(::get_protocol_version());
} }
@ -248,10 +265,17 @@ static void *keyserver_thread_routine(void *arg)
JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startKeyserverLookup( JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startKeyserverLookup(
JNIEnv *env, JNIEnv *env,
jobject me jobject obj
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
pthread_t *thread = nullptr; pthread_t *thread = nullptr;
locked_queue< pEp_identity * > *queue = nullptr; locked_queue< pEp_identity * > *queue = nullptr;
@ -267,16 +291,16 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startKeyser
return; return;
} }
thread = (pthread_t *) env->GetLongField(me, thread_handle); thread = (pthread_t *) env->GetLongField(obj, thread_handle);
if (thread) if (thread)
return; return;
thread = (pthread_t *) calloc(1, sizeof(pthread_t)); thread = (pthread_t *) calloc(1, sizeof(pthread_t));
assert(thread); assert(thread);
env->SetLongField(me, thread_handle, (jlong) thread); env->SetLongField(obj, thread_handle, (jlong) thread);
queue = new locked_queue< pEp_identity * >(); 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); register_examine_function(Adapter::session(), examine_identity, (void *) queue);
@ -285,10 +309,17 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startKeyser
JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_stopKeyserverLookup( JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_stopKeyserverLookup(
JNIEnv *env, JNIEnv *env,
jobject me jobject obj
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
pthread_t *thread = nullptr; pthread_t *thread = nullptr;
locked_queue< pEp_identity * > *queue = nullptr; locked_queue< pEp_identity * > *queue = nullptr;
@ -304,14 +335,14 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_stopKeyserv
return; return;
} }
thread = (pthread_t *) env->GetLongField(me, thread_handle); thread = (pthread_t *) env->GetLongField(obj, thread_handle);
if (!thread) if (!thread)
return; 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(obj, queue_handle, (jlong) 0);
env->SetLongField(me, thread_handle, (jlong) 0); env->SetLongField(obj, thread_handle, (jlong) 0);
register_examine_function(Adapter::session(), nullptr, nullptr); register_examine_function(Adapter::session(), nullptr, nullptr);
@ -322,9 +353,17 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_stopKeyserv
JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startSync( JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startSync(
JNIEnv *env, JNIEnv *env,
jobject me jobject obj
) )
{ {
std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
pEpLog("######## starting sync"); pEpLog("######## starting sync");
try { try {
Adapter::startup<JNISync>(messageToSend, notifyHandshake, &o, &JNISync::onSyncStartup, &JNISync::onSyncShutdown); Adapter::startup<JNISync>(messageToSend, notifyHandshake, &o, &JNISync::onSyncStartup, &JNISync::onSyncShutdown);
@ -337,19 +376,33 @@ JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_startSync(
JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_stopSync( JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_stopSync(
JNIEnv *env, JNIEnv *env,
jobject me jobject obj
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
Adapter::shutdown(); Adapter::shutdown();
} }
JNIEXPORT jboolean JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_isSyncRunning( JNIEXPORT jboolean JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_isSyncRunning(
JNIEnv *env, JNIEnv *env,
jobject me jobject obj
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
return (jboolean) Adapter::is_sync_running(); return (jboolean) Adapter::is_sync_running();
} }

5
src/foundation_pEp_jniadapter__Blob.cc

@ -1,11 +1,6 @@
#include <pEp/bloblist.h>
#include <pEp/sync_codec.h> #include <pEp/sync_codec.h>
#include <pEp/distribution_codec.h> #include <pEp/distribution_codec.h>
#include <pEp/pEpLog.hh> #include <pEp/pEpLog.hh>
#include <iostream>
#include <cstring>
#include <cassert>
#include "jniutils.hh" #include "jniutils.hh"
#include "throw_pEp_exception.hh" #include "throw_pEp_exception.hh"
#include "foundation_pEp_jniadapter__Blob.h" #include "foundation_pEp_jniadapter__Blob.h"

11
src/gen_cpp_Engine.ysl2

@ -9,8 +9,6 @@ tstylesheet {
template "interface" document("foundation_pEp_jniadapter_{@name}.cc", "text") template "interface" document("foundation_pEp_jniadapter_{@name}.cc", "text")
|| ||
#include <assert.h>
#include <pEp/message_api.h>
#include <pEp/blacklist.h> #include <pEp/blacklist.h>
#include <pEp/openpgp_compat.h> #include <pEp/openpgp_compat.h>
#include <pEp/key_reset.h> #include <pEp/key_reset.h>
@ -50,7 +48,14 @@ tstylesheet {
jobject obj`apply "parm[in|inout]", mode=sig` jobject obj`apply "parm[in|inout]", mode=sig`
) )
{ {
pEpLog("called"); std::mutex *mutex_local = nullptr;
{
std::lock_guard<std::mutex> l(global_mutex);
pEpLog("called with lock_guard");
mutex_local = get_engine_java_object_mutex(env, obj);
}
std::lock_guard<std::mutex> l(*mutex_local);
|| ||
apply "parm[in|inout]", mode=in; apply "parm[in|inout]", mode=in;

7
src/gen_cpp_Message.ysl2

@ -12,15 +12,8 @@ tstylesheet {
document("foundation_pEp_jniadapter_{$jname}.cc", "text") { document("foundation_pEp_jniadapter_{$jname}.cc", "text") {
|| ||
#include <exception>
#include <new>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <pEp/«@name».h>
#include <pEp/mime.h> #include <pEp/mime.h>
#include <pEp/pEpLog.hh> #include <pEp/pEpLog.hh>
#include "jniutils.hh" #include "jniutils.hh"
#include "throw_pEp_exception.hh" #include "throw_pEp_exception.hh"
#include "foundation_pEp_jniadapter_«$jname».h" #include "foundation_pEp_jniadapter_«$jname».h"

3
src/identity_api.cc

@ -1,7 +1,4 @@
#include <pEp/message_api.h>
#include <pEp/pEpLog.hh> #include <pEp/pEpLog.hh>
#include "jniutils.hh"
extern "C" { extern "C" {

56
src/jniutils.cc

@ -1,11 +1,5 @@
#include "jniutils.hh" #include "jniutils.hh"
#include <stdexcept> #include <pEp/pEpLog.hh>
#include <typeinfo>
#include <time.h>
#include <stdlib.h>
#include <assert.h>
#include <string>
#ifndef __LP64__ #ifndef __LP64__
#include <time64.h> #include <time64.h>
#define time_t time64_t #define time_t time64_t
@ -17,6 +11,54 @@
namespace pEp { namespace pEp {
namespace JNIAdapter { namespace JNIAdapter {
std::mutex global_mutex;
std::unordered_map<long, std::mutex*> engine_objid_mutex;
std::mutex* get_engine_java_object_mutex(
JNIEnv *env,
jobject obj
)
{
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("found mutex: " << engine_obj_mutex << " with native_handle: " << engine_obj_mutex->native_handle());
assert(engine_obj_mutex);
return engine_obj_mutex;
}
void create_engine_java_object_mutex(
JNIEnv *env,
jobject obj
)
{
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 id: " << engine_obj_id);
assert(engine_obj_mutex);
if(engine_objid_mutex.count(engine_obj_id) > 0) {
pEpLog("Fatal: mutex already existing for object id: " << engine_obj_id);
assert(0);
}
engine_objid_mutex.insert(std::make_pair(engine_obj_id, engine_obj_mutex ));
}
void release_engine_java_object_mutex(
JNIEnv *env,
jobject obj
)
{
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_objid_mutex.erase(engine_obj_id);
delete engine_obj_mutex;
}
jclass findClass(JNIEnv *env, const char *classname) jclass findClass(JNIEnv *env, const char *classname)
{ {
jclass clazz = env->FindClass(classname); jclass clazz = env->FindClass(classname);

39
src/jniutils.hh

@ -1,8 +1,6 @@
#pragma once #pragma once
#include <unordered_map>
#include <list> #include <thread>
#include <pthread.h>
#include <errno.h>
#include <jni.h> #include <jni.h>
#include <pEp/stringpair.h> #include <pEp/stringpair.h>
#include <pEp/identity_list.h> #include <pEp/identity_list.h>
@ -15,11 +13,42 @@
#define LOG_TAG "pEpJNIAdapter" #define LOG_TAG "pEpJNIAdapter"
#define LOGD(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#else #else
#define LOGD(...) #define LOGD(...) do{}while(0)
#endif #endif
namespace pEp { namespace pEp {
namespace JNIAdapter { 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<long, std::mutex*> engine_objid_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); jclass findClass(JNIEnv *env, const char *classname);
jfieldID getFieldID( jfieldID getFieldID(

4
test/java/foundation/pEp/jniadapter/test/jni88/TestMain.java

@ -89,8 +89,8 @@ class TestThread extends Thread {
class TestMain { class TestMain {
public static void main(String[] args) { public static void main(String[] args) {
// Test parameters // Test parameters
boolean useSharedEngine = true; boolean useSharedEngine = false;
int numThreads = 2; int numThreads = 200;
int numIters = 1000000000; int numIters = 1000000000;
Engine sharedEngine = null; Engine sharedEngine = null;

98
test/java/foundation/pEp/jniadapter/test/jni92/TestMain.java

@ -4,6 +4,7 @@ import foundation.pEp.jniadapter.*;
import java.lang.Thread; import java.lang.Thread;
import java.util.Vector; import java.util.Vector;
import java.util.function.Consumer;
/* /*
@ -14,24 +15,29 @@ https://pep.foundation/jira/browse/JNI-81
*/ */
class TestThread extends Thread { class TestThread extends Thread {
TestThread(String threadName) { int nrEngines = 1;
boolean useSharedEngines = false;
TestThread(String threadName, int nrEngines, boolean useSharedEngines) {
Thread.currentThread().setName(threadName); Thread.currentThread().setName(threadName);
this.nrEngines = nrEngines;
this.useSharedEngines = useSharedEngines;
} }
public void run() { public void run() {
TestUtils.logH1( "Thread Starting"); TestUtils.logH1( "Thread Starting");
TestMain.TestMainRun(2); TestMain.TestMainRun(nrEngines, useSharedEngines);
} }
} }
class TestMain { class TestMain {
static Vector<Engine> sharedEngines;
public static Engine createNewEngine() throws pEpException { public static Engine createNewEngine() throws pEpException {
Engine e; Engine e;
TestUtils.logH2("Creating new Engine"); TestUtils.logH2("Creating new Engine");
e = new Engine(); e = new Engine();
TestUtils.log("Engine created\n"); TestUtils.log("Engine created with java object ID: " + e.getId());
return e; return e;
} }
@ -43,51 +49,73 @@ class TestMain {
return ev; return ev;
} }
public static void own_identities_retrieve_on_EngineVector(Vector<Engine> ev) { public static void engineConsumer(Vector<Engine> ev, Consumer<Engine> ec) {
ev.forEach(e -> { ev.forEach(e -> {
TestUtils.logH2("own_identities_retrieve()"); TestUtils.logH2("engineConsumer: on engine java object ID: " + e.getId());
e.own_identities_retrieve(); ec.accept(e);
TestUtils.log("\n");
}); });
} }
public static void TestMainRun(int nrEngines, boolean useSharedEngines) {
Consumer<Engine> c = (e) -> {
Vector<Identity> 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("");
};
public static void TestMainRun(int nrEngines) { if(useSharedEngines) {
Vector<Engine> engineVector = TestMain.createEngines(nrEngines); TestMain.engineConsumer(sharedEngines, c);
// TestUtils.sleep(200); } else {
TestMain.own_identities_retrieve_on_EngineVector(engineVector); Vector<Engine> threadLocalEngines = TestMain.createEngines(nrEngines);
TestMain.engineConsumer(threadLocalEngines, c);
}
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) {
TestUtils.logH1("JNI-92 Starting"); TestUtils.logH1("JNI-92 Starting");
TestUtils.setLoggingEnabled(false);
int nrTestruns = 1000;
boolean multiThreaded = true; boolean multiThreaded = true;
int nrEngines = 3; boolean useSharedEngines = true;
int nrThreads = 100;
if (!multiThreaded) { int nrEnginesPerThread = 1;
// Single Threaded
TestMainRun(nrEngines);
} else {
// Mutli Threaded
Vector<TestThread> tts = new Vector<TestThread>();
int nrThreads = nrEngines;
for (int i = 0; i < nrThreads; i++) {
tts.add(new TestThread("TestThread-" + i));
// TestUtils.sleep(200);
}
tts.forEach(t -> { if(useSharedEngines) {
t.start(); sharedEngines = TestMain.createEngines(nrEnginesPerThread);
// TestUtils.sleep(2000); }
});
tts.forEach(t -> { for (int run = 0; run < nrTestruns; run++ ) {
try { TestUtils.logH1("Testrun Nr: " + run);
t.join(); if (!multiThreaded) {
} catch (Exception e) { // Single Threaded
TestUtils.log("Exception joining thread" + e.toString()); TestMainRun(nrEnginesPerThread, useSharedEngines);
} else {
// Mutli Threaded
Vector<TestThread> tts = new Vector<TestThread>();
for (int i = 0; i < nrThreads; i++) {
tts.add(new TestThread("TestThread-" + i, nrEnginesPerThread, useSharedEngines));
} }
});
tts.forEach(t -> {
t.start();
});
tts.forEach(t -> {
try {
t.join();
} catch (Exception e) {
TestUtils.log("Exception joining thread" + e.toString());
}
});
}
TestUtils.logH1("Testrun DONE" );
System.gc();
// TestUtils.sleep(2000);
} }
} }
} }

20
test/java/foundation/pEp/jniadapter/test/utils/TestUtils.java

@ -22,10 +22,24 @@ public class TestUtils {
return ret; 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) { public static void log(String msg) {
String threadNameFmt = String.format("%-10s", Thread.currentThread().getName()); if(logEnabled) {
String msgOut = threadNameFmt + ": " + msg; String threadNameFmt = String.format("%-10s", Thread.currentThread().getName());
System.out.println(msgOut); String msgOut = threadNameFmt + ": " + msg;
System.out.println(msgOut);
}
} }
public static void logH1(String msg) { public static void logH1(String msg) {

Loading…
Cancel
Save