1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

Internal JNI refactoring towards consolidating support for callbacks with and without finalizers.

FossilOrigin-Name: 120983a570d6de055cef9d916096de3410897ea9f46d23ea6eff1f9b549e423a
This commit is contained in:
stephan
2023-07-30 17:24:01 +00:00
parent 72bb29283f
commit 91710673e7
4 changed files with 68 additions and 59 deletions

View File

@ -332,23 +332,27 @@ static void JNIEnvCache_clear(JNIEnvCache * p){
memset(p, 0, sizeof(JNIEnvCache)); memset(p, 0, sizeof(JNIEnvCache));
} }
/**
State for binding Java-side busy handlers.
*/
typedef struct {
JNIEnv * env; /* env registered from */;
jobject jObj /* BusyHandler instance */;
jclass klazz /* jObj's class */;
jmethodID jmidxCallback /* klazz's xCallback method */;
} BusyHandlerJni;
/** State for various hook callbacks. */ /** State for various hook callbacks. */
typedef struct JniHookState JniHookState; typedef struct JniHookState JniHookState;
struct JniHookState{ struct JniHookState{
jobject jObj; jobject jObj /* global ref to Java instance */;
jmethodID midCallback; jmethodID midCallback /* callback method */;
}; };
/**
State for binding Java-side callbacks which potentially have an
xDestroy() method. Maintenance reminder: this is different from
JniHookState because of the need to look up the finalizer. TODO:
look into consolidating this with JniHookState, perhaps adding the
jclass member to that object.
*/
typedef struct JniHookStateWithDtor JniHookStateWithDtor;
struct JniHookStateWithDtor{
JniHookState base;
jclass klazz /* jObj's class */;
};
/** /**
Per-(sqlite3*) state for bindings which do not have their own Per-(sqlite3*) state for bindings which do not have their own
finalizer functions, e.g. tracing and commit/rollback hooks. This finalizer functions, e.g. tracing and commit/rollback hooks. This
@ -381,7 +385,7 @@ struct PerDbStateJni {
JniHookState rollbackHook; JniHookState rollbackHook;
JniHookState updateHook; JniHookState updateHook;
JniHookState collationNeeded; JniHookState collationNeeded;
BusyHandlerJni busyHandler; JniHookStateWithDtor busyHandler;
}; };
static struct { static struct {
@ -455,38 +459,39 @@ static int s3jni_db_error(sqlite3*db, int err_code, const char *zMsg){
any exceptions it throws. This is a no-op of s has no current any exceptions it throws. This is a no-op of s has no current
state. state.
*/ */
static void BusyHandlerJni_clear(BusyHandlerJni * const s){ static void JniHookStateWithDtor_clear(JNIEnv *env, JniHookStateWithDtor * const s){
if(s->jObj){ if(s->base.jObj){
JNIEnv * const env = s->env;
const jmethodID method = const jmethodID method =
(*env)->GetMethodID(env, s->klazz, "xDestroy", "()V"); (*env)->GetMethodID(env, s->klazz, "xDestroy", "()V");
if(method){ if(method){
(*env)->CallVoidMethod(env, s->jObj, method); (*env)->CallVoidMethod(env, s->base.jObj, method);
IFTHREW_CLEAR; IFTHREW{
EXCEPTION_WARN_CALLBACK_THREW;
EXCEPTION_CLEAR;
}
}else{ }else{
EXCEPTION_CLEAR; EXCEPTION_CLEAR;
} }
UNREF_G(s->jObj); UNREF_G(s->base.jObj);
UNREF_G(s->klazz); UNREF_G(s->klazz);
memset(s, 0, sizeof(BusyHandlerJni)); memset(s, 0, sizeof(JniHookStateWithDtor));
} }
} }
/** /**
Initializes s to wrap BusyHandlerJni-type object jObject, clearning Initializes s to wrap JniHookStateWithDtor-type object jObject, clearing
any current state of s beforehand. Returns 0 on success, non-0 on any current state of s beforehand. Returns 0 on success, non-0 on
error. On error, s's state is cleared. error. On error, s's state is cleared.
*/ */
static int BusyHandlerJni_init(JNIEnv * const env, BusyHandlerJni * const s, static int JniHookStateWithDtor_init(JNIEnv * const env, JniHookStateWithDtor * const s,
jobject jObj){ jobject jObj){
const char * zSig = "(I)I" /* callback signature */; const char * zSig = "(I)I" /* callback signature */;
if(s->jObj) BusyHandlerJni_clear(s); if(s->base.jObj) JniHookStateWithDtor_clear(env, s);
s->env = env; s->base.jObj = REF_G(jObj);
s->jObj = REF_G(jObj);
s->klazz = REF_G((*env)->GetObjectClass(env, jObj)); s->klazz = REF_G((*env)->GetObjectClass(env, jObj));
s->jmidxCallback = (*env)->GetMethodID(env, s->klazz, "xCallback", zSig); s->base.midCallback = (*env)->GetMethodID(env, s->klazz, "xCallback", zSig);
IFTHREW { IFTHREW {
BusyHandlerJni_clear(s); JniHookStateWithDtor_clear(env, s);
return SQLITE_ERROR; return SQLITE_ERROR;
} }
return 0; return 0;
@ -702,6 +707,11 @@ static PerDbStateJni * PerDbStateJni_alloc(JNIEnv *env, sqlite3 *pDb, jobject jD
return rv; return rv;
} }
static void JniHookState_unref(JNIEnv * const env, JniHookState * const s){
UNREF_G(s->jObj);
//UNREF_G_(s->klazz);
}
/** /**
Clears s's state and moves it to the free-list. Clears s's state and moves it to the free-list.
*/ */
@ -720,12 +730,15 @@ static void PerDbStateJni_set_aside(PerDbStateJni * const s){
assert(!s->pPrev); assert(!s->pPrev);
S3Global.perDb.aUsed = s->pNext; S3Global.perDb.aUsed = s->pNext;
} }
UNREF_G(s->trace.jObj); #define UNHOOK(MEMBER) JniHookState_unref(env, &s->MEMBER)
UNREF_G(s->progress.jObj); UNHOOK(trace);
UNREF_G(s->commitHook.jObj); UNHOOK(progress);
UNREF_G(s->rollbackHook.jObj); UNHOOK(commitHook);
UNHOOK(rollbackHook);
UNHOOK(updateHook);
#undef UNHOOK
UNREF_G(s->jDb); UNREF_G(s->jDb);
BusyHandlerJni_clear(&s->busyHandler); JniHookStateWithDtor_clear(env, &s->busyHandler);
memset(s, 0, sizeof(PerDbStateJni)); memset(s, 0, sizeof(PerDbStateJni));
s->pNext = S3Global.perDb.aFree; s->pNext = S3Global.perDb.aFree;
if(s->pNext) s->pNext->pPrev = s; if(s->pNext) s->pNext->pPrev = s;
@ -742,8 +755,7 @@ static void PerDbStateJni_dump(PerDbStateJni *s){
MARKER(("PerDbStateJni->progress.jObj @ %p\n", s->progress.jObj)); MARKER(("PerDbStateJni->progress.jObj @ %p\n", s->progress.jObj));
MARKER(("PerDbStateJni->commitHook.jObj @ %p\n", s->commitHook.jObj)); MARKER(("PerDbStateJni->commitHook.jObj @ %p\n", s->commitHook.jObj));
MARKER(("PerDbStateJni->rollbackHook.jObj @ %p\n", s->rollbackHook.jObj)); MARKER(("PerDbStateJni->rollbackHook.jObj @ %p\n", s->rollbackHook.jObj));
MARKER(("PerDbStateJni->busyHandler.env @ %p\n", s->busyHandler.env)); MARKER(("PerDbStateJni->busyHandler.jObj @ %p\n", s->busyHandler.base.jObj));
MARKER(("PerDbStateJni->busyHandler.jObj @ %p\n", s->busyHandler.jObj));
MARKER(("PerDbStateJni->env @ %p\n", s->env)); MARKER(("PerDbStateJni->env @ %p\n", s->env));
} }
@ -1392,10 +1404,10 @@ JDECL(jint,1bind_1zeroblob64)(JENV_JSELF, jobject jpStmt,
static int s3jni_busy_handler(void* pState, int n){ static int s3jni_busy_handler(void* pState, int n){
PerDbStateJni * const ps = (PerDbStateJni *)pState; PerDbStateJni * const ps = (PerDbStateJni *)pState;
int rc = 0; int rc = 0;
if( ps->busyHandler.jObj ){ if( ps->busyHandler.base.jObj ){
JNIEnv * const env = ps->env; JNIEnv * const env = ps->env;
rc = (*env)->CallIntMethod(env, ps->busyHandler.jObj, rc = (*env)->CallIntMethod(env, ps->busyHandler.base.jObj,
ps->busyHandler.jmidxCallback, (jint)n); ps->busyHandler.base.midCallback, (jint)n);
IFTHREW_CLEAR; IFTHREW_CLEAR;
} }
return rc; return rc;
@ -1406,20 +1418,20 @@ JDECL(jint,1busy_1handler)(JENV_JSELF, jobject jDb, jobject jBusy){
int rc; int rc;
if(!ps) return (jint)SQLITE_NOMEM; if(!ps) return (jint)SQLITE_NOMEM;
if(jBusy){ if(jBusy){
if(ps->busyHandler.jObj && if(ps->busyHandler.base.jObj &&
(*env)->IsSameObject(env, ps->busyHandler.jObj, jBusy)){ (*env)->IsSameObject(env, ps->busyHandler.base.jObj, jBusy)){
/* Same object - this is a no-op. */ /* Same object - this is a no-op. */
return 0; return 0;
} }
rc = BusyHandlerJni_init(env, &ps->busyHandler, jBusy); rc = JniHookStateWithDtor_init(env, &ps->busyHandler, jBusy);
if(rc){ if(rc){
assert(!ps->busyHandler.jObj); assert(!ps->busyHandler.base.jObj);
return (jint)rc; return (jint)rc;
} }
assert(ps->busyHandler.jObj && ps->busyHandler.klazz); assert(ps->busyHandler.base.jObj && ps->busyHandler.klazz);
assert( (*env)->IsSameObject(env, ps->busyHandler.jObj, jBusy) ); assert( (*env)->IsSameObject(env, ps->busyHandler.base.jObj, jBusy) );
}else{ }else{
BusyHandlerJni_clear(&ps->busyHandler); JniHookStateWithDtor_clear(env, &ps->busyHandler);
} }
return jBusy return jBusy
? sqlite3_busy_handler(ps->pDb, s3jni_busy_handler, ps) ? sqlite3_busy_handler(ps->pDb, s3jni_busy_handler, ps)
@ -1429,8 +1441,8 @@ JDECL(jint,1busy_1handler)(JENV_JSELF, jobject jDb, jobject jBusy){
JDECL(jint,1busy_1timeout)(JENV_JSELF, jobject jDb, jint ms){ JDECL(jint,1busy_1timeout)(JENV_JSELF, jobject jDb, jint ms){
PerDbStateJni * const ps = PerDbStateJni_for_db(env, jDb, 0, 0); PerDbStateJni * const ps = PerDbStateJni_for_db(env, jDb, 0, 0);
if( ps ){ if( ps ){
if( ps->busyHandler.jObj ){ if( ps->busyHandler.base.jObj ){
BusyHandlerJni_clear(&ps->busyHandler); JniHookStateWithDtor_clear(env, &ps->busyHandler);
} }
return sqlite3_busy_timeout(ps->pDb, (int)ms); return sqlite3_busy_timeout(ps->pDb, (int)ms);
} }

View File

@ -20,8 +20,8 @@ import java.lang.annotation.ElementType;
/** /**
This annotation is for flagging parameters which may legally be This annotation is for flagging parameters which may legally be
null, noting that they may behave different if passed null but are null, noting that they may behave differently if passed null but
prepared to expect null as a value. are prepared to expect null as a value.
This annotation is solely for the reader's information. This annotation is solely for the reader's information.
*/ */
@ -271,9 +271,6 @@ public final class SQLite3Jni {
public static native int sqlite3_collation_needed(@NotNull sqlite3 db, public static native int sqlite3_collation_needed(@NotNull sqlite3 db,
@Nullable CollationNeeded callback); @Nullable CollationNeeded callback);
//TODO public static native int sqlite3_collation_needed16(
// sqlite3 db, void(*)(void*,sqlite3*,int eTextRep,const void*)
public static native sqlite3 sqlite3_context_db_handle(@NotNull sqlite3_context cx); public static native sqlite3 sqlite3_context_db_handle(@NotNull sqlite3_context cx);
public static native CommitHook sqlite3_commit_hook(@NotNull sqlite3 db, @Nullable CommitHook hook); public static native CommitHook sqlite3_commit_hook(@NotNull sqlite3 db, @Nullable CommitHook hook);

View File

@ -1,5 +1,5 @@
C Mark\sthe\sJava\swrapper\sclasses\sof\sthe\sC-native\stypes\sas\s'final'\s(cannot\sbe\ssubclassed). C Internal\sJNI\srefactoring\stowards\sconsolidating\ssupport\sfor\scallbacks\swith\sand\swithout\sfinalizers.
D 2023-07-30T13:47:51.705 D 2023-07-30T17:24:01.771
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -232,7 +232,7 @@ F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
F ext/jni/GNUmakefile 56a014dbff9516774d895ec1ae9df0ed442765b556f79a0fc0b5bc438217200d F ext/jni/GNUmakefile 56a014dbff9516774d895ec1ae9df0ed442765b556f79a0fc0b5bc438217200d
F ext/jni/README.md c0e6e80935e7761acead89b69c87765b23a6bcb2858c321c3d05681fd338292a F ext/jni/README.md c0e6e80935e7761acead89b69c87765b23a6bcb2858c321c3d05681fd338292a
F ext/jni/src/c/sqlite3-jni.c d3ce5d96feb5eebf8dd171f041704798f3d0a5da1ee93a43788059d1d9f167ff F ext/jni/src/c/sqlite3-jni.c 5334b9a85288fbe2750234001f0054a700d8b3e996b7353c03f1f0231a55ac6f
F ext/jni/src/c/sqlite3-jni.h 28def286ee305c1c89a43ac5918a6862d985d0534f7ccbbd74df4885d3918b73 F ext/jni/src/c/sqlite3-jni.h 28def286ee305c1c89a43ac5918a6862d985d0534f7ccbbd74df4885d3918b73
F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c
F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1 F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1
@ -243,7 +243,7 @@ F ext/jni/src/org/sqlite/jni/OutputPointer.java c7868f1f4ad63435ee44d409377df7dd
F ext/jni/src/org/sqlite/jni/ProgressHandler.java 5979450e996416d28543f1d42634d308439565a99332a8bd84e424af667116cc F ext/jni/src/org/sqlite/jni/ProgressHandler.java 5979450e996416d28543f1d42634d308439565a99332a8bd84e424af667116cc
F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564 F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
F ext/jni/src/org/sqlite/jni/SQLFunction.java 663a4e479ec65bfbf893586439e12d30b8237898064a22ab64f5658b57315f37 F ext/jni/src/org/sqlite/jni/SQLFunction.java 663a4e479ec65bfbf893586439e12d30b8237898064a22ab64f5658b57315f37
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 42ca7686d009a56e4f5ceb74a0bd32ca69c025f2bf30d3e906696ad36ac72510 F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 829a6409d6fa5e82b39d85df5f14643c93dff383978ccbf35dc4af3ba29b6e62
F ext/jni/src/org/sqlite/jni/Tester1.java 1690172fccafbf8d8170b55b950003db182265c26dbb5a510122ec46a44d2611 F ext/jni/src/org/sqlite/jni/Tester1.java 1690172fccafbf8d8170b55b950003db182265c26dbb5a510122ec46a44d2611
F ext/jni/src/org/sqlite/jni/Tracer.java c2fe1eba4a76581b93b375a7b95ab1919e5ae60accfb06d6beb067b033e9bae1 F ext/jni/src/org/sqlite/jni/Tracer.java c2fe1eba4a76581b93b375a7b95ab1919e5ae60accfb06d6beb067b033e9bae1
F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d
@ -2071,8 +2071,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 41fb5898f1a78d9fd85a020e28a6048a7359b54e35632e9072917cbdbcd8b07d P 4fd3d93623d67c25fb8a490e0d4ea56d531d858067011ab1b28cce694098feff
R 5feab867f7054c182eed540fcab703e8 R bc4ee4f83b4e96887d3ad46ea5a5d938
U stephan U stephan
Z deb68695eee2433aa355b2bf6487020e Z ea19c30c280d92414c0f0555fd56a50e
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
4fd3d93623d67c25fb8a490e0d4ea56d531d858067011ab1b28cce694098feff 120983a570d6de055cef9d916096de3410897ea9f46d23ea6eff1f9b549e423a