]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Resolve a JNI-side race condition. Removed a now-extraneous struct member. Internal...
authorstephan <stephan@noemail.net>
Mon, 28 Aug 2023 13:06:26 +0000 (13:06 +0000)
committerstephan <stephan@noemail.net>
Mon, 28 Aug 2023 13:06:26 +0000 (13:06 +0000)
FossilOrigin-Name: f5274e00f17d58e075f90ae5c1d4b38933da315e51592171fa35bcbd67b40b2a

ext/jni/src/c/sqlite3-jni.c
ext/jni/src/org/sqlite/jni/Tester1.java
manifest
manifest.uuid

index 00138ba40031dd934bf58bef07ecec0a537ded9c..632db79e4a93fa69fd5a119945a569edd8cbd185 100644 (file)
@@ -297,8 +297,8 @@ static inline void s3jni_unref_local(JNIEnv * const env, jobject const v){
 /*
 ** Key type for use with S3JniGlobal_nph().
 */
-typedef struct S3NphRef S3NphRef;
-struct S3NphRef {
+typedef struct S3JniNphRef S3JniNphRef;
+struct S3JniNphRef {
   const int index             /* index into S3JniGlobal.nph[] */;
   const char * const zName    /* Full Java name of the class */;
   const char * const zMember  /* Name of member property */;
@@ -312,25 +312,25 @@ struct S3NphRef {
 ** corresponds to its index in the S3JniGlobal.nph[] array.
 */
 static const struct {
-  const S3NphRef sqlite3;
-  const S3NphRef sqlite3_stmt;
-  const S3NphRef sqlite3_context;
-  const S3NphRef sqlite3_value;
-  const S3NphRef OutputPointer_Int32;
-  const S3NphRef OutputPointer_Int64;
-  const S3NphRef OutputPointer_sqlite3;
-  const S3NphRef OutputPointer_sqlite3_stmt;
-  const S3NphRef OutputPointer_sqlite3_value;
+  const S3JniNphRef sqlite3;
+  const S3JniNphRef sqlite3_stmt;
+  const S3JniNphRef sqlite3_context;
+  const S3JniNphRef sqlite3_value;
+  const S3JniNphRef OutputPointer_Int32;
+  const S3JniNphRef OutputPointer_Int64;
+  const S3JniNphRef OutputPointer_sqlite3;
+  const S3JniNphRef OutputPointer_sqlite3_stmt;
+  const S3JniNphRef OutputPointer_sqlite3_value;
 #ifdef SQLITE_ENABLE_FTS5
-  const S3NphRef OutputPointer_String;
-  const S3NphRef OutputPointer_ByteArray;
-  const S3NphRef Fts5Context;
-  const S3NphRef Fts5ExtensionApi;
-  const S3NphRef fts5_api;
-  const S3NphRef fts5_tokenizer;
-  const S3NphRef Fts5Tokenizer;
+  const S3JniNphRef OutputPointer_String;
+  const S3JniNphRef OutputPointer_ByteArray;
+  const S3JniNphRef Fts5Context;
+  const S3JniNphRef Fts5ExtensionApi;
+  const S3JniNphRef fts5_api;
+  const S3JniNphRef fts5_tokenizer;
+  const S3JniNphRef Fts5Tokenizer;
 #endif
-} S3NphRefs = {
+} S3JniNphRefs = {
 #define MkRef(INDEX, KLAZZ, MEMBER, SIG) \
   { INDEX, "org/sqlite/jni/" KLAZZ, MEMBER, SIG }
 /* NativePointerHolder ref */
@@ -368,10 +368,10 @@ enum {
   ** Size of the NativePointerHolder cache.  Need enough space for
   ** (only) the library's NativePointerHolder and OutputPointer types,
   ** a fixed count known at build-time.  This value needs to be
-  ** exactly the number of S3NphRef entries in the S3NphRefs
+  ** exactly the number of S3JniNphRef entries in the S3JniNphRefs
   ** object.
   */
-  S3Jni_NphCache_size = sizeof(S3NphRefs) / sizeof(S3NphRef)
+  S3Jni_NphCache_size = sizeof(S3JniNphRefs) / sizeof(S3JniNphRef)
 };
 
 /*
@@ -382,7 +382,7 @@ enum {
 */
 typedef struct S3JniNphClass S3JniNphClass;
 struct S3JniNphClass {
-  volatile const S3NphRef * pRef /* Entry from S3NphRefs. */;
+  volatile const S3JniNphRef * pRef /* Entry from S3JniNphRefs. */;
   jclass klazz                /* global ref to the concrete
                               ** NativePointerHolder subclass
                               ** represented by zClassName */;
@@ -580,9 +580,7 @@ struct S3JniGlobalType {
     S3JniDb * aFree  /* Linked list of free instances */;
     sqlite3_mutex * mutex /* mutex for aHead and aFree */;
     void const * locker /* perDb mutex is held on this object's
-                           behalf.  Unlike envCache.locker, we cannot
-                           always have this set to the current JNIEnv
-                           object. Used only for sanity checking. */;
+                           behalf. Used only for sanity checking. */;
   } perDb;
   struct {
     S3JniUdf * aFree    /* Head of the free-item list. Guarded by global
@@ -593,7 +591,6 @@ struct S3JniGlobalType {
   ** and never released.
   */
   struct {
-    jclass cObj              /* global ref to java.lang.Object */;
     jclass cLong             /* global ref to java.lang.Long */;
     jclass cString           /* global ref to java.lang.String */;
     jobject oCharsetUtf8     /* global ref to StandardCharset.UTF_8 */;
@@ -637,13 +634,13 @@ struct S3JniGlobalType {
 #ifdef SQLITE_JNI_ENABLE_METRICS
   /* Internal metrics. */
   struct {
-    volatile unsigned envCacheHits;
-    volatile unsigned envCacheMisses;
-    volatile unsigned envCacheAllocs;
+    volatile unsigned nEnvHit;
+    volatile unsigned nEnvMiss;
+    volatile unsigned nEnvAlloc;
+    volatile unsigned nNphInit;
     volatile unsigned nMutexEnv       /* number of times envCache.mutex was entered for
                                          a S3JniEnv operation. */;
-    volatile unsigned nMutexEnv2      /* number of times envCache.mutex was entered for
-                                         a S3JniNphClass operation. */;
+    volatile unsigned nMutexEnv2      /* number of times envCache.mutex was entered */;
     volatile unsigned nMutexPerDb     /* number of times perDb.mutex was entered */;
     volatile unsigned nMutexAutoExt   /* number of times autoExt.mutex was entered */;
     volatile unsigned nMutexGlobal    /* number of times global mutex was entered. */;
@@ -687,7 +684,7 @@ static S3JniGlobalType S3JniGlobal = {};
 ** argument is a Java sqlite3 object, as this operation only has void
 ** pointers to work with.
 */
-#define PtrGet_T(T,OBJ) NativePointerHolder_get(OBJ, &S3NphRefs.T)
+#define PtrGet_T(T,OBJ) NativePointerHolder_get(OBJ, &S3JniNphRefs.T)
 #define PtrGet_sqlite3(OBJ) PtrGet_T(sqlite3, OBJ)
 #define PtrGet_sqlite3_stmt(OBJ) PtrGet_T(sqlite3_stmt, OBJ)
 #define PtrGet_sqlite3_value(OBJ) PtrGet_T(sqlite3_value, OBJ)
@@ -828,12 +825,12 @@ static S3JniEnv * S3JniEnv__get(JNIEnv * const env){
   row = SJG.envCache.aHead;
   for( ; row; row = row->pNext ){
     if( row->env == env ){
-      s3jni_incr( &SJG.metrics.envCacheHits );
+      s3jni_incr( &SJG.metrics.nEnvHit );
       S3JniMutex_Env_leave;
       return row;
     }
   }
-  s3jni_incr( &SJG.metrics.envCacheMisses );
+  s3jni_incr( &SJG.metrics.nEnvMiss );
   row = SJG.envCache.aFree;
   if( row ){
     assert(!row->pPrev);
@@ -841,7 +838,7 @@ static S3JniEnv * S3JniEnv__get(JNIEnv * const env){
     if( row->pNext ) row->pNext->pPrev = 0;
   }else{
     row = s3jni_malloc_or_die(env, sizeof(*row));
-    s3jni_incr( &SJG.metrics.envCacheAllocs );
+    s3jni_incr( &SJG.metrics.nEnvAlloc );
   }
   memset(row, 0, sizeof(*row));
   row->pNext = SJG.envCache.aHead;
@@ -1015,7 +1012,7 @@ static jstring s3jni_text16_to_jstring(JNIEnv * const env, const void * const p,
 **  System.out.println(e.toString()); // java.lang.RuntimeException: Hi
 **  System.out.println(e.getMessage()); // Hi
 */
-static char * s3jni_exception_error_msg(JNIEnv * const env, jthrowable jx ){
+static char * s3jni_exception_error_msg(JNIEnv * const env, jthrowable jx){
   jmethodID mid;
   jstring msg;
   char * zMsg;
@@ -1243,7 +1240,7 @@ static int S3JniEnv_uncache(JNIEnv * const env){
 ** This simple cache catches >99% of searches in the current
 ** (2023-07-31) tests.
 */
-static S3JniNphClass * S3JniGlobal__nph(JNIEnv * const env, S3NphRef const* pRef){
+static S3JniNphClass * S3JniGlobal__nph(JNIEnv * const env, S3JniNphRef const* pRef){
   /**
    According to:
 
@@ -1260,18 +1257,24 @@ static S3JniNphClass * S3JniGlobal__nph(JNIEnv * const env, S3NphRef const* pRef
      cached as well.
   */
   S3JniNphClass * const pNC = &SJG.nph[pRef->index];
-  assert( (void*)pRef>=(void*)&S3NphRefs && (void*)pRef<(void*)(&S3NphRefs + 1)
+  assert( (void*)pRef>=(void*)&S3JniNphRefs && (void*)pRef<(void*)(&S3JniNphRefs + 1)
           && "pRef is out of range." );
+  assert( pRef->index>=0
+          && (pRef->index < (sizeof(S3JniNphRefs) / sizeof(S3JniNphRef))) );
   if( !pNC->pRef ){
     S3JniMutex_Nph_enter;
     if( !pNC->pRef ){
-      pNC->pRef = pRef;
-      pNC->klazz = (*env)->FindClass(env, pRef->zName);
+      jclass const klazz = (*env)->FindClass(env, pRef->zName);
       S3JniExceptionIsFatal("FindClass() unexpectedly threw");
-      pNC->klazz = S3JniRefGlobal(pNC->klazz);
+      pNC->klazz = S3JniRefGlobal(klazz);
+      s3jni_incr( &SJG.metrics.nNphInit );
+      pNC->pRef = pRef
+        /* Must come last to avoid a race condition where pNC->klass
+           can be NULL after this function returns. */;
     }
     S3JniMutex_Nph_leave;
   }
+  assert( pNC->klazz );
   return pNC;
 }
 
@@ -1282,11 +1285,13 @@ static S3JniNphClass * S3JniGlobal__nph(JNIEnv * const env, S3NphRef const* pRef
 ** NativePointerHolder<T> class.
 */
 static jfieldID NativePointerHolder_field(JNIEnv * const env,
-                                          S3NphRef const* pRef){
+                                          S3JniNphRef const* pRef){
   S3JniNphClass * const pNC = S3JniGlobal_nph(pRef);
+  assert( pNC->klazz );
   if( !pNC->fidValue ){
     S3JniMutex_Nph_enter;
     if( !pNC->fidValue ){
+      s3jni_incr( &SJG.metrics.nNphInit );
       pNC->fidValue = (*env)->GetFieldID(env, pNC->klazz,
                                          pRef->zMember, pRef->zTypeSig);
       S3JniExceptionIsFatal("Code maintenance required: missing "
@@ -1302,7 +1307,7 @@ static jfieldID NativePointerHolder_field(JNIEnv * const env,
 ** zClassName must be a static string so we can use its address
 ** as a cache key.
 */
-static void NativePointerHolder__set(JNIEnv * env, S3NphRef const* pRef,
+static void NativePointerHolder__set(JNIEnv * env, S3JniNphRef const* pRef,
                                     jobject ppOut, const void * p){
   jfieldID const fid = NativePointerHolder_field(env, pRef);
   S3JniMutex_Nph_enter;
@@ -1320,7 +1325,7 @@ static void NativePointerHolder__set(JNIEnv * env, S3NphRef const* pRef,
 ** cache key. This is a no-op if pObj is NULL.
 */
 static void * NativePointerHolder__get(JNIEnv * env, jobject pObj,
-                                       S3NphRef const* pRef){
+                                       S3JniNphRef const* pRef){
   if( pObj ){
     jfieldID const fid = NativePointerHolder_field(env, pRef);
     void * rv;
@@ -1467,7 +1472,7 @@ static int S3JniAutoExtension_init(JNIEnv *const env,
 
 /*
 ** Common init for OutputPointer_set_Int32() and friends. pRef must be
-** a pointer from S3NphRefs. jOut must be an instance of that
+** a pointer from S3JniNphRefs. jOut must be an instance of that
 ** class. If necessary, this fetches the jfieldID for jOut's [value]
 ** property, which must be of the type represented by the JNI type
 ** signature zTypeSig, and stores it in pRef's S3JniGlobal.nph entry.
@@ -1478,13 +1483,14 @@ static int S3JniAutoExtension_init(JNIEnv *const env,
 ** routine with the same pRef but different zTypeSig: it will
 ** misbehave.
 */
-static jfieldID OutputPointer_field(JNIEnv * const env, S3NphRef const * pRef){
+static jfieldID OutputPointer_field(JNIEnv * const env, S3JniNphRef const * pRef){
   S3JniNphClass * const pNC = S3JniGlobal_nph(pRef);
 
   assert( pNC->klazz );
   if( !pNC->fidValue ){
     S3JniMutex_Nph_enter;
     if( !pNC->fidValue ){
+      s3jni_incr( &SJG.metrics.nNphInit );
       pNC->fidValue = (*env)->GetFieldID(env, pNC->klazz, pRef->zMember, pRef->zTypeSig);
       S3JniExceptionIsFatal("OutputPointer_field() could not find OutputPointer.*.value");
     }
@@ -1501,7 +1507,7 @@ static void OutputPointer_set_Int32(JNIEnv * const env, jobject const jOut,
                                     int v){
   (*env)->SetIntField(env, jOut,
                       OutputPointer_field(
-                        env, &S3NphRefs.OutputPointer_Int32
+                        env, &S3JniNphRefs.OutputPointer_Int32
                       ), (jint)v);
   S3JniExceptionIsFatal("Cannot set OutputPointer.Int32.value");
 }
@@ -1514,7 +1520,7 @@ static void OutputPointer_set_Int64(JNIEnv * const env, jobject const jOut,
                                     jlong v){
   (*env)->SetLongField(env, jOut,
                        OutputPointer_field(
-                         env, &S3NphRefs.OutputPointer_Int64
+                         env, &S3JniNphRefs.OutputPointer_Int64
                        ), v);
   S3JniExceptionIsFatal("Cannot set OutputPointer.Int64.value");
 }
@@ -1524,7 +1530,7 @@ static void OutputPointer_set_Int64(JNIEnv * const env, jobject const jOut,
 ** Object type.
 */
 static void OutputPointer_set_obj(JNIEnv * const env,
-                                  S3NphRef const * const pRef,
+                                  S3JniNphRef const * const pRef,
                                   jobject const jOut,
                                   jobject v){
   (*env)->SetObjectField(env, jOut, OutputPointer_field(env, pRef), v);
@@ -1537,7 +1543,7 @@ static void OutputPointer_set_obj(JNIEnv * const env,
 */
 static void OutputPointer_set_sqlite3(JNIEnv * const env, jobject const jOut,
                                       jobject jDb){
-  OutputPointer_set_obj(env, &S3NphRefs.OutputPointer_sqlite3, jOut, jDb);
+  OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_sqlite3, jOut, jDb);
 }
 
 /*
@@ -1546,7 +1552,7 @@ static void OutputPointer_set_sqlite3(JNIEnv * const env, jobject const jOut,
 */
 static void OutputPointer_set_sqlite3_stmt(JNIEnv * const env, jobject const jOut,
                                            jobject jStmt){
-  OutputPointer_set_obj(env, &S3NphRefs.OutputPointer_sqlite3_stmt, jOut, jStmt);
+  OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_sqlite3_stmt, jOut, jStmt);
 }
 
 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
@@ -1556,7 +1562,7 @@ static void OutputPointer_set_sqlite3_stmt(JNIEnv * const env, jobject const jOu
 */
 static void OutputPointer_set_sqlite3_value(JNIEnv * const env, jobject const jOut,
                                             jobject jValue){
-  OutputPointer_set_obj(env, &S3NphRefs.OutputPointer_sqlite3_value, jOut, jValue);
+  OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_sqlite3_value, jOut, jValue);
 }
 #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
 
@@ -1568,7 +1574,7 @@ static void OutputPointer_set_sqlite3_value(JNIEnv * const env, jobject const jO
 */
 static void OutputPointer_set_ByteArray(JNIEnv * const env, jobject const jOut,
                                         jbyteArray const v){
-  OutputPointer_set_obj(env, &S3NphRefs.OutputPointer_ByteArray, jOut, v);
+  OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_ByteArray, jOut, v);
 }
 #endif
 
@@ -1578,7 +1584,7 @@ static void OutputPointer_set_ByteArray(JNIEnv * const env, jobject const jOut,
 */
 static void OutputPointer_set_String(JNIEnv * const env, jobject const jOut,
                                      jstring const v){
-  OutputPointer_set_obj(env, &S3NphRefs.OutputPointer_String, jOut, v);
+  OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_String, jOut, v);
 }
 #endif /* SQLITE_ENABLE_FTS5 */
 
@@ -1661,16 +1667,17 @@ static void ResultJavaValue_finalizer(void *v){
 ** if Java fails to allocate, but the JNI docs are not entirely clear
 ** on that detail.
 **
-** Always use a static pointer from the S3NphRefs struct for the 2nd
+** Always use a static pointer from the S3JniNphRefs struct for the 2nd
 ** argument so that we can use pRef->index as an O(1) cache key.
 */
-static jobject new_NativePointerHolder_object(JNIEnv * const env, S3NphRef const * pRef,
+static jobject new_NativePointerHolder_object(JNIEnv * const env, S3JniNphRef const * pRef,
                                               const void * pNative){
   jobject rv = 0;
   S3JniNphClass * const pNC = S3JniGlobal_nph(pRef);
   if( !pNC->midCtor ){
     S3JniMutex_Nph_enter;
     if( !pNC->midCtor ){
+      s3jni_incr( &SJG.metrics.nNphInit );
       pNC->midCtor = (*env)->GetMethodID(env, pNC->klazz, "<init>", "()V");
       S3JniExceptionIsFatal("Cannot find constructor for class.");
     }
@@ -1684,16 +1691,16 @@ static jobject new_NativePointerHolder_object(JNIEnv * const env, S3NphRef const
 }
 
 static inline jobject new_sqlite3_wrapper(JNIEnv * const env, sqlite3 *sv){
-  return new_NativePointerHolder_object(env, &S3NphRefs.sqlite3, sv);
+  return new_NativePointerHolder_object(env, &S3JniNphRefs.sqlite3, sv);
 }
 static inline jobject new_sqlite3_context_wrapper(JNIEnv * const env, sqlite3_context *sv){
-  return new_NativePointerHolder_object(env, &S3NphRefs.sqlite3_context, sv);
+  return new_NativePointerHolder_object(env, &S3JniNphRefs.sqlite3_context, sv);
 }
 static inline jobject new_sqlite3_stmt_wrapper(JNIEnv * const env, sqlite3_stmt *sv){
-  return new_NativePointerHolder_object(env, &S3NphRefs.sqlite3_stmt, sv);
+  return new_NativePointerHolder_object(env, &S3JniNphRefs.sqlite3_stmt, sv);
 }
 static inline jobject new_sqlite3_value_wrapper(JNIEnv * const env, sqlite3_value *sv){
-  return new_NativePointerHolder_object(env, &S3NphRefs.sqlite3_value, sv);
+  return new_NativePointerHolder_object(env, &S3JniNphRefs.sqlite3_value, sv);
 }
 
 /* Helper typedefs for UDF callback types. */
@@ -1816,10 +1823,8 @@ static int udf_args(JNIEnv *env,
   *jArgv = 0;
   if( !jcx ) goto error_oom;
   ja = (*env)->NewObjectArray(
-    env, argc, SJG.g.cObj
-    /* S3JniGlobal_nph(&S3NphRefs.sqlite3_value)->klazz would be
-       more correct, but it unpredictably triggers an assert in the
-       JVM. */, NULL);
+    env, argc, S3JniGlobal_nph(&S3JniNphRefs.sqlite3_value)->klazz,
+    NULL);
   s3jni_oom_check( ja );
   if( !ja ) goto error_oom;
   for(i = 0; i < argc; ++i){
@@ -2106,7 +2111,7 @@ static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
   assert( !ps->pDb && "it's still being opened" );
   assert( ps->jDb );
   ps->pDb = pDb;
-  NativePointerHolder_set(&S3NphRefs.sqlite3, ps->jDb, pDb)
+  NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, pDb)
     /* As of here, the Java/C connection is complete */;
   for( i = 0; go && 0==rc; ++i ){
     S3JniAutoExtension ax = {0,0}
@@ -2423,7 +2428,7 @@ static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){
     if( 0==rc ){
       S3JniDb_set_aside(ps)
         /* MUST come after close() because of ps->trace. */;
-      NativePointerHolder_set(&S3NphRefs.sqlite3, jDb, 0);
+      NativePointerHolder_set(&S3JniNphRefs.sqlite3, jDb, 0);
     }
   }
 #else
@@ -2446,7 +2451,7 @@ static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){
       if( 0==rc ){
         S3JniDb__set_aside_unlocked(env,ps)
           /* MUST come after close() because of ps->trace. */;
-        NativePointerHolder_set(&S3NphRefs.sqlite3, jDb, 0);
+        NativePointerHolder_set(&S3JniNphRefs.sqlite3, jDb, 0);
       }
     }else{
       /* ps is from S3Global.perDb.aFree. */
@@ -3100,7 +3105,7 @@ S3JniApi(sqlite3_finalize(),jint,1finalize)(
   sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jpStmt);
   if( pStmt ){
     rc = sqlite3_finalize(pStmt);
-    NativePointerHolder_set(&S3NphRefs.sqlite3_stmt, jpStmt, 0);
+    NativePointerHolder_set(&S3JniNphRefs.sqlite3_stmt, jpStmt, 0);
   }
   return rc;
 }
@@ -3205,7 +3210,7 @@ static int s3jni_open_post(JNIEnv * const env, S3JniEnv * const jc,
     assert(ps->jDb);
     if( 0==ps->pDb ){
       ps->pDb = *ppDb;
-      NativePointerHolder_set(&S3NphRefs.sqlite3, ps->jDb, *ppDb)
+      NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, *ppDb)
         /* As of here, the Java/C connection is complete */;
     }else{
       assert( ps->pDb==*ppDb
@@ -3310,7 +3315,7 @@ end:
       OutputPointer_set_Int32(env, outTail, (int)(zTail ? (zTail - (const char *)pBuf) : 0));
     }
     if( pStmt ){
-      NativePointerHolder_set(&S3NphRefs.sqlite3_stmt, jStmt, pStmt);
+      NativePointerHolder_set(&S3JniNphRefs.sqlite3_stmt, jStmt, pStmt);
     }else{
       /* Happens for comments and whitespace. */
       S3JniUnrefLocal(jStmt);
@@ -4256,7 +4261,7 @@ JniDecl(void,1jni_1internal_1details)(JniArgsEnvClass){
   SO(S3JniEnv);
   SO(S3JniHook);
   SO(S3JniDb);
-  SO(S3NphRefs);
+  SO(S3JniNphRefs);
   printf("\t(^^^ %u NativePointerHolder subclasses)\n",
          (unsigned)S3Jni_NphCache_size);
   SO(S3JniGlobal);
@@ -4266,19 +4271,20 @@ JniDecl(void,1jni_1internal_1details)(JniArgsEnvClass){
 #ifdef SQLITE_JNI_ENABLE_METRICS
   printf("Cache info:\n");
   printf("\tJNIEnv cache: %u allocs, %u misses, %u hits\n",
-         SJG.metrics.envCacheAllocs,
-         SJG.metrics.envCacheMisses,
-         SJG.metrics.envCacheHits);
+         SJG.metrics.nEnvAlloc, SJG.metrics.nEnvMiss,
+         SJG.metrics.nEnvHit);
   printf("Mutex entry:"
          "\n\tglobal       = %u"
          "\n\tenv          = %u"
-         "\n\tnph          = %u"
+         "\n\tnph          = %u (%u for S3JniNphClass init, rest for "
+                                "native pointer access)"
          "\n\tperDb        = %u"
          "\n\tautoExt list = %u"
          "\n\tS3JniUdf free-list = %u"
          "\n\tmetrics      = %u\n",
          SJG.metrics.nMutexGlobal, SJG.metrics.nMutexEnv,
-         SJG.metrics.nMutexEnv2, SJG.metrics.nMutexPerDb,
+         SJG.metrics.nMutexEnv2, SJG.metrics.nNphInit,
+         SJG.metrics.nMutexPerDb,
          SJG.metrics.nMutexAutoExt, SJG.metrics.nMutexUdf,
          SJG.metrics.nMetrics);
   puts("Allocs:");
@@ -4290,6 +4296,9 @@ JniDecl(void,1jni_1internal_1details)(JniArgsEnvClass){
          SJG.metrics.nUdfAlloc, (unsigned) sizeof(S3JniUdf),
          (unsigned)(SJG.metrics.nUdfAlloc * sizeof(S3JniUdf)),
          SJG.metrics.nUdfRecycled);
+  printf("\tS3JniEnv: %u alloced (*%u = %u bytes)\n",
+         SJG.metrics.nEnvAlloc, (unsigned) sizeof(S3JniEnv),
+         (unsigned)(SJG.metrics.nEnvAlloc * sizeof(S3JniEnv)));
   puts("Java-side UDF calls:");
 #define UDF(T) printf("\t%-8s = %u\n", "x" #T, SJG.metrics.udf.n##T)
   UDF(Func); UDF(Step); UDF(Final); UDF(Value); UDF(Inverse);
@@ -4324,10 +4333,10 @@ JniDecl(void,1jni_1internal_1details)(JniArgsEnvClass){
   JNIEXPORT ReturnType JNICALL                  \
   JniFuncNameFtsTok(Suffix)
 
-#define PtrGet_fts5_api(OBJ) NativePointerHolder_get(OBJ,&S3NphRefs.fts5_api)
-#define PtrGet_fts5_tokenizer(OBJ) NativePointerHolder_get(OBJ,&S3NphRefs.fts5_tokenizer)
-#define PtrGet_Fts5Context(OBJ) NativePointerHolder_get(OBJ,&S3NphRefs.Fts5Context)
-#define PtrGet_Fts5Tokenizer(OBJ) NativePointerHolder_get(OBJ,&S3NphRefs.Fts5Tokenizer)
+#define PtrGet_fts5_api(OBJ) NativePointerHolder_get(OBJ,&S3JniNphRefs.fts5_api)
+#define PtrGet_fts5_tokenizer(OBJ) NativePointerHolder_get(OBJ,&S3JniNphRefs.fts5_tokenizer)
+#define PtrGet_Fts5Context(OBJ) NativePointerHolder_get(OBJ,&S3JniNphRefs.Fts5Context)
+#define PtrGet_Fts5Tokenizer(OBJ) NativePointerHolder_get(OBJ,&S3JniNphRefs.Fts5Tokenizer)
 #define Fts5ExtDecl Fts5ExtensionApi const * const fext = s3jni_ftsext()
 
 /**
@@ -4389,10 +4398,10 @@ static inline Fts5ExtensionApi const * s3jni_ftsext(void){
 }
 
 static inline jobject new_Fts5Context_wrapper(JNIEnv * const env, Fts5Context *sv){
-  return new_NativePointerHolder_object(env, &S3NphRefs.Fts5Context, sv);
+  return new_NativePointerHolder_object(env, &S3JniNphRefs.Fts5Context, sv);
 }
 static inline jobject new_fts5_api_wrapper(JNIEnv * const env, fts5_api *sv){
-  return new_NativePointerHolder_object(env, &S3NphRefs.fts5_api, sv);
+  return new_NativePointerHolder_object(env, &S3JniNphRefs.fts5_api, sv);
 }
 
 /*
@@ -4402,7 +4411,7 @@ static inline jobject new_fts5_api_wrapper(JNIEnv * const env, fts5_api *sv){
 static jobject s3jni_getFts5ExensionApi(JNIEnv * const env){
   if( !SJG.fts5.jFtsExt ){
     jobject pNPH = new_NativePointerHolder_object(
-      env, &S3NphRefs.Fts5ExtensionApi, s3jni_ftsext()
+      env, &S3JniNphRefs.Fts5ExtensionApi, s3jni_ftsext()
     );
     S3JniMutex_Env_enter;
     if( pNPH ){
@@ -4829,7 +4838,7 @@ static int s3jni_xTokenize_xToken(void *p, int tFlags, const char* z,
 ** Proxy for Fts5ExtensionApi.xTokenize() and
 ** fts5_tokenizer.xTokenize()
 */
-static jint s3jni_fts5_xTokenize(JniArgsEnvObj, S3NphRef const *pRef,
+static jint s3jni_fts5_xTokenize(JniArgsEnvObj, S3JniNphRef const *pRef,
                                  jint tokFlags, jobject jFcx,
                                  jbyteArray jbaText, jobject jCallback){
   Fts5ExtDecl;
@@ -4857,11 +4866,11 @@ static jint s3jni_fts5_xTokenize(JniArgsEnvObj, S3NphRef const *pRef,
   s.tok.jba = S3JniRefLocal(jbaText);
   s.tok.zPrev = (const char *)pText;
   s.tok.nPrev = (int)nText;
-  if( pRef == &S3NphRefs.Fts5ExtensionApi ){
+  if( pRef == &S3JniNphRefs.Fts5ExtensionApi ){
     rc = fext->xTokenize(PtrGet_Fts5Context(jFcx),
                          (const char *)pText, (int)nText,
                          &s, s3jni_xTokenize_xToken);
-  }else if( pRef == &S3NphRefs.fts5_tokenizer ){
+  }else if( pRef == &S3JniNphRefs.fts5_tokenizer ){
     fts5_tokenizer * const pTok = PtrGet_fts5_tokenizer(jSelf);
     rc = pTok->xTokenize(PtrGet_Fts5Tokenizer(jFcx), &s, tokFlags,
                          (const char *)pText, (int)nText,
@@ -4879,13 +4888,13 @@ static jint s3jni_fts5_xTokenize(JniArgsEnvObj, S3NphRef const *pRef,
 
 JniDeclFtsXA(jint,xTokenize)(JniArgsEnvObj,jobject jFcx, jbyteArray jbaText,
                              jobject jCallback){
-  return s3jni_fts5_xTokenize(env, jSelf, &S3NphRefs.Fts5ExtensionApi,
+  return s3jni_fts5_xTokenize(env, jSelf, &S3JniNphRefs.Fts5ExtensionApi,
                               0, jFcx, jbaText, jCallback);
 }
 
 JniDeclFtsTok(jint,xTokenize)(JniArgsEnvObj,jobject jFcx, jint tokFlags,
                               jbyteArray jbaText, jobject jCallback){
-  return s3jni_fts5_xTokenize(env, jSelf, &S3NphRefs.Fts5Tokenizer,
+  return s3jni_fts5_xTokenize(env, jSelf, &S3JniNphRefs.Fts5Tokenizer,
                               tokFlags, jFcx, jbaText, jCallback);
 }
 
@@ -5168,9 +5177,6 @@ Java_org_sqlite_jni_SQLite3Jni_init(JniArgsEnvClass){
   }
 
   /* Grab references to various global classes and objects... */
-  SJG.g.cObj = S3JniRefGlobal((*env)->FindClass(env,"java/lang/Object"));
-  S3JniExceptionIsFatal("Error getting reference to Object class.");
-
   SJG.g.cLong = S3JniRefGlobal((*env)->FindClass(env,"java/lang/Long"));
   S3JniExceptionIsFatal("Error getting reference to Long class.");
   SJG.g.ctorLong1 = (*env)->GetMethodID(env, SJG.g.cLong,
index 496a90a4282950dc41dabd1d4e278bc636d5a771..3d60362f61a46c511b6e1c5e2477de2ef0578e7f 100644 (file)
@@ -1496,25 +1496,6 @@ public class Tester1 implements Runnable {
       }
     }
 
-    {
-      // Build list of tests to run from the methods named test*().
-      testMethods = new ArrayList<>();
-      for(final java.lang.reflect.Method m : Tester1.class.getDeclaredMethods()){
-        final String name = m.getName();
-        if( name.equals("testFail") ){
-          if( forceFail ){
-            testMethods.add(m);
-          }
-        }else if( !m.isAnnotationPresent( ManualTest.class ) ){
-          if( nThread>1 && m.isAnnotationPresent( SingleThreadOnly.class ) ){
-            outln("Skipping test in multi-thread mode: ",name,"()");
-          }else if( name.startsWith("test") ){
-            testMethods.add(m);
-          }
-        }
-      }
-    }
-
     if( sqlLog ){
       if( sqlite3_compileoption_used("ENABLE_SQLLOG") ){
         int rc = sqlite3_config( new ConfigSqllogCallback() {
@@ -1538,6 +1519,27 @@ public class Tester1 implements Runnable {
           "you are very likely seeing the side effects of a known openjdk8 ",
           "bug. It is unsightly but does not affect the library.");
 
+    {
+      // Build list of tests to run from the methods named test*().
+      testMethods = new ArrayList<>();
+      out("Skipping tests in multi-thread mode:");
+      for(final java.lang.reflect.Method m : Tester1.class.getDeclaredMethods()){
+        final String name = m.getName();
+        if( name.equals("testFail") ){
+          if( forceFail ){
+            testMethods.add(m);
+          }
+        }else if( !m.isAnnotationPresent( ManualTest.class ) ){
+          if( nThread>1 && m.isAnnotationPresent( SingleThreadOnly.class ) ){
+            out(" "+name+"()");
+          }else if( name.startsWith("test") ){
+            testMethods.add(m);
+          }
+        }
+      }
+      out("\n");
+    }
+
     final long timeStart = System.currentTimeMillis();
     int nLoop = 0;
     switch( SQLITE_THREADSAFE ){ /* Sanity checking */
index 1878e12f38537e990766a76777a08d34f5538896..70e5a027811119a0781ceb3336258079bb84d972 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\san\sissue\swith\sinfinity\shandling\sby\sthe\sSUM()\sfunction\sthat\sgoes\sback\nto\sthe\sextended-precision\sSUM()\senhancement\sof\n[check-in\sc63e26e705f5e967].\s\sProblem\sreported\sby\n[forum:/forumpost/1c06ddcacc86032a|forum\spost\s1c06ddcacc86032a].
-D 2023-08-28T12:20:18.225
+C Resolve\sa\sJNI-side\srace\scondition.\sRemoved\sa\snow-extraneous\sstruct\smember.\sInternal\sAPI\srenaming\sfor\sconsistency.
+D 2023-08-28T13:06:26.423
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -236,7 +236,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
 F ext/jni/GNUmakefile 374873bf6d2cd6ceafb458e28b59140dbb074f01f7adddf7e15a3ee3daf44551
 F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9
 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
-F ext/jni/src/c/sqlite3-jni.c c8f329d225c87c9af2c74508e6be48424a380502da7bca82fc7486dd91a7af9c
+F ext/jni/src/c/sqlite3-jni.c 59c06b99420d61baf03004fc47093e786bde383ffe5d70e1458443e095a4fd78
 F ext/jni/src/c/sqlite3-jni.h 12e1a5ef5ee1795dc22577c285b4518dfd8aa4af45757f6cb81a555d967bf201
 F ext/jni/src/org/sqlite/jni/AbstractCollationCallback.java 95e88ba04f4aac51ffec65693e878e234088b2f21b387f4e4285c8b72b33e436
 F ext/jni/src/org/sqlite/jni/AggregateFunction.java 7312486bc65fecdb91753c0a4515799194e031f45edbe16a6373cea18f404dc4
@@ -263,7 +263,7 @@ F ext/jni/src/org/sqlite/jni/SQLFunction.java 544a875d33fd160467d82e2397ac33157b
 F ext/jni/src/org/sqlite/jni/SQLite3CallbackProxy.java c2748ab52856075b053a55b317988d95dc7fb4d3d42520f8c33573effe1cd185
 F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 440d64e8c4cff53bd3c0cc676381212489198302d7f1aaa535712c2d7163cc69
 F ext/jni/src/org/sqlite/jni/ScalarFunction.java 6d387bb499fbe3bc13c53315335233dbf6a0c711e8fa7c521683219b041c614c
-F ext/jni/src/org/sqlite/jni/Tester1.java 8653c7b0b50116cf9bd8bf19b83b3e76896b75df09f5debe57a70c556d90203b
+F ext/jni/src/org/sqlite/jni/Tester1.java a9558165dbb085494705525ef28e41d337d8348bf44259ce1f77cad72547bfdf
 F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629
 F ext/jni/src/org/sqlite/jni/TraceV2Callback.java 641926b05a772c2c05c842a81aa839053ba4a13b78ef04b402f5705d060c6246
 F ext/jni/src/org/sqlite/jni/UpdateHookCallback.java be2bc96ff4f56b3c1fd18ae7dba9b207b25b6c123b8a5fd2f7aaf3cc208d8b7d
@@ -2106,8 +2106,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P a0d0f1aafc6086726131dff5e6628f2771c20db3122a53bdbb82945ab5d326d1
-R fb83093e6e2cb948f127cf0c2e1878f8
-U drh
-Z 71db94e565d6eff1a32422e7510ceb2f
+P 77d3dcd283595c52f24c07fc59ba60c9133b71c440cf3f799cf48c907c6fae3e
+R 09b3f39e435c1ed6b663c3c2289d1181
+U stephan
+Z e20dad0d4d283548754a87d23449f696
 # Remove this line to create a well-formed Fossil manifest.
index 803fdb75137d31af123a82ef739c57c4b1233f71..752861a24dbede21ba79e78a9a8ba58c2e2ea334 100644 (file)
@@ -1 +1 @@
-77d3dcd283595c52f24c07fc59ba60c9133b71c440cf3f799cf48c907c6fae3e
\ No newline at end of file
+f5274e00f17d58e075f90ae5c1d4b38933da315e51592171fa35bcbd67b40b2a
\ No newline at end of file