[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
gthread-jni-error-handling.patch
From: |
Steven Augart |
Subject: |
gthread-jni-error-handling.patch |
Date: |
Fri, 16 Jul 2004 13:34:25 -0400 |
User-agent: |
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031007 |
--
Steven Augart
Jikes RVM, a free, open source, Virtual Machine:
http://oss.software.ibm.com/jikesrvm
This patch only modifies gthread-jni.c, the portable-native-sync support.
1) Improves error reporting from the NEW_TROUBLE macro
2) Fixes an incorrect assumption -- EnterMonitor and ExitMonitor do
not normally throw exceptions (although they might in Jikes RVM --
this may or may not be a violation of the spec; I'm not sure.)
ChangeLog:
2004-07-03 Steven Augart <address@hidden>
* native/jni/gtk-peer/gthread-jni.c: Doc fixes.
(vfatalMsg): New Function.
(vcriticalMsg): New Function.
(fatalMsg): Now a wrapper around vfatalMsg().
(criticalMsg): Now a wrapper around vcriticalMsg().
(vthrow): New function.
(throw): Now a wrapper around vthrow().
(throw): MESSAGE argument is now a full printf-style format string.
(throw): Now takes arbitrary additional arguments.
(NEW_TROUBLE2): New macro.
(HIDE_OLD_TROUBLE): Assertion disabled by default
(SHOW_OLD_TROUBLE): (env) now passed as an argument.
(enterMonitor): Bug fix; MonitorEnter does not have to throw
exceptions when it fails.
(enterMonitor): Now manually throws an exception on failure.
(enterMonitor): Improved error messages.
(exitMonitor): Similar bug fix.
(*): Control flow changes throughout to reflect that
enterMonitor() and exitMonitor() now throw exceptions.
Index: native/jni/gtk-peer/gthread-jni.c
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/gtk-peer/gthread-jni.c,v
retrieving revision 1.14
diff -I*.class -u -r1.14 gthread-jni.c
--- native/jni/gtk-peer/gthread-jni.c 9 Jul 2004 10:37:33 -0000 1.14
+++ native/jni/gtk-peer/gthread-jni.c 16 Jul 2004 17:32:34 -0000
@@ -128,9 +128,7 @@
#define EXPLAIN_TROUBLE 1 /* Describe any unexpected trouble that
happens. This is a superset
of EXPLAIN_BROKEN, and if set trumps an
- unset EXPLAIN_BROKEN. It is not a strict
- superset, since at the moment there is no
- TROUBLE that is not also BROKEN.
+ unset EXPLAIN_BROKEN.
Use criticalMsg() to describe the problem.
*/
@@ -145,21 +143,21 @@
/** Error Handling **/
#define DIE_IF_BROKEN 1 /* Dies if serious trouble happens. There is
- really no non-serious trouble, except
+ very little non-serious trouble, except
possibly problems that arise during
pthread_create, which are reported by a
GError.
- If you do not set DIE_IF_BROKEN, then
- trouble will raise a Java RuntimeException.
- We probably do want to die right away,
- since anything that's BROKEN really
- indicates a programming error or a
- system-wide error, and that's what the glib
- documentation says you should do in case of
- that kind of error in a glib-style
- function. But it does work to turn this
- off. */
+ If you do not set DIE_IF_BROKEN, then the
+ TROUBLE routines will raise a Java
+ RuntimeException. We probably do want to
+ die right away, since anything that's
+ BROKEN really indicates a programming error
+ or a system-wide error, and the glib
+ documentation says you should die right
+ away in case of that kind of error in a
+ glib-style function. But it does work to
+ turn this off. */
#if DIE_IF_BROKEN
#define DIE_IF_BADLY_BROKEN 1 /* DIE_IF_BROKEN implies DIE_IF_BADLY_BROKEN */
@@ -183,8 +181,9 @@
#define DELETE_LOCAL_REFS 1 /* Whether to delete local references.
JNI only guarantees that there wil be 16
- available. (Jikes RVM provides an number
- only limited by VM memory.)
+ available. (Jikes RVM pushes them on the
+ stack, and so provides an number only
+ limited by available stack space.)
Jikes RVM will probably perform faster if
this is turned off, but other VMs may need
@@ -233,13 +232,23 @@
/* Forward Declarations for Functions */
static int threadObj_set_priority (JNIEnv * env, jobject threadObj,
GThreadPriority gpriority);
+
+static int vthrow (JNIEnv * env, jthrowable cause, const char *message,
+ gboolean isBroken, const char *file, int line, va_list ap);
+
+
static void fatalMsg (const char fmt[], ...)
__attribute__ ((format (printf, 1, 2)))
__attribute__ ((noreturn));
+static void vfatalMsg (const char fmt[], va_list ap)
+ __attribute__ ((noreturn));
+
static void criticalMsg (const char fmt[], ...)
__attribute__ ((format (printf, 1, 2)));
+static void vcriticalMsg (const char fmt[], va_list ap);
+
static void tracing (const char fmt[], ...)
__attribute__ ((format (printf, 1, 2)));
@@ -299,8 +308,15 @@
{
va_list ap;
va_start (ap, fmt);
+ vfatalMsg (fmt, ap);
+ /* We don't need this: va_end (ap); */
+}
+
+
+static void
+vfatalMsg (const char fmt[], va_list ap)
+{
vfprintf (stderr, fmt, ap);
- va_end (ap);
fputs ("\nAborting execution\n", stderr);
abort ();
}
@@ -311,11 +327,19 @@
{
va_list ap;
va_start (ap, fmt);
- vfprintf (stderr, fmt, ap);
+ vcriticalMsg (fmt, ap);
va_end (ap);
- putc ('\n', stderr);
}
+
+static void
+vcriticalMsg (const char fmt[], va_list ap)
+{
+ vfprintf (stderr, fmt, ap);
+ putc('\n', stderr);
+}
+
+
/* Unlike the other two, this one does not append a newline. This is only
used if one of the TRACE_ macros is defined. */
static void
@@ -382,23 +406,47 @@
isBroken is always true in this case. */
static int
throw (JNIEnv * env, jthrowable cause, const char *message,
- gboolean isBroken, const char *file, int line)
+ gboolean isBroken, const char *file, int line, ...)
{
- jstring jmessage;
+ va_list ap;
+ int retval;
+
+ va_start (ap, line);
+ retval = vthrow (env, cause, message, isBroken, file, line, ap);
+ va_end (ap);
+ return retval;
+}
+
+
+/* Throw a new RuntimeException. It may wrap around an existing exception.
+ 1 if we did rethrow, -1 if we had trouble while rethrowing.
+ isBroken is always true in this case. This version takes variable
+ arguments. */
+static int
+vthrow (JNIEnv * env, jthrowable cause, const char *message,
+ gboolean isBroken, const char *file, int line,
+ /* Any extra args for MESSAGE. */
+ va_list ap)
+{
+ jstring jmessage = NULL;
gboolean describedException = FALSE; /* Did we already describe the
exception to stderr or the
equivalent? */
jthrowable wrapper;
/* allocate local message in Java */
- const char fmt[] = "In AWT JNI, %s (at %s:%d)";
- size_t len = strlen (message) + strlen (file) + sizeof fmt + 25;
- char *buf;
+ const char fmt[] = "In AWT JNI, %s (at %s:%d)"; /* message, file, line */
+ size_t len = 0xCCCCCCCC; /* how many chars does a buf need to be?
+ Init to garbage. */
+ char *msgbuf = NULL;
+ char *bigbuf = NULL;
+ int retval; /* return val from this func */
if (EXPLAIN_TROUBLE || (isBroken && EXPLAIN_BROKEN))
{
- criticalMsg ("%s:%d: AWT JNI failure%s: %s\n", file, line,
- isBroken ? " (BROKEN)" : "", message);
+ fprintf (stderr, "%s:%d: AWT JNI failure%s: ", file, line,
+ isBroken ? " (BROKEN)" : "");
+ vcriticalMsg (message, ap);
if (cause)
{
jthrowable currentException = (*env)->ExceptionOccurred (env);
@@ -415,7 +463,8 @@
{
BADLY_BROKEN1
("Relaunching an exception with Throw failed.");
- return -1;
+ retval = -1;
+ goto done;
}
}
else
@@ -428,23 +477,34 @@
}
} /* if (EXPLAIN_TROUBLE) */
- if (isBroken && DIE_IF_BROKEN)
- fatalMsg ("%s:%d: Aborting execution; BROKEN: %s\n", file, line, message);
-
- if ((buf = malloc (len)))
+ if (isBroken && DIE_IF_BROKEN)
{
- bzero (buf, len);
- snprintf (buf, len, fmt, message, file, line);
- jmessage = (*env)->NewStringUTF (env, buf);
- free (buf);
- }
- else
- {
- jmessage = NULL;
+ fprintf (stderr, "%s:%d: Aborting execution; BROKEN: ", file, line);
+ vfatalMsg (message, ap);
}
+ /* Generate the caller-specified message. */
+ len = vsnprintf (NULL, 0, message, ap) + 1;
+ msgbuf = malloc ( len ); /* free at function's end */
+ if ( ! msgbuf )
+ goto no_message;
+ (void) vsnprintf (msgbuf, len, message, ap);
+
+ /* Generate the bigger message; insert the caller-specified message. */
+ len = snprintf (NULL, 0, fmt, msgbuf, file, line) + 1;
+ bigbuf = malloc ( len ); /* free at function's end */
+ if ( ! bigbuf )
+ goto no_message;
+
+ (void) snprintf (bigbuf, len, fmt, msgbuf, file, line);
+ /* Note: we only use ASCII in our code's error messages, so NewStringUTF
+ is safe, and appropriate. */
+ jmessage = (*env)->NewStringUTF (env, bigbuf);
+
+ no_message:
+
/* Create the RuntimeException wrapper object and throw it. It is OK for
- CAUSE to be NULL. */
+ either or both of CAUSE and JMESSAGE to be NULL. */
wrapper = (jthrowable) (*env)->NewObject
(env, runtimeException_class, runtimeException_ctor, jmessage, cause);
DELETE_LOCAL_REF (env, jmessage);
@@ -462,14 +522,15 @@
" a new java.lang.RuntimeException.");
criticalMsg ("We were trying to warn about the following"
" previous failure:");
- criticalMsg ("%s:%d: %s", file, line, message);
+ criticalMsg ("%s:%d: In AWT JNI: %s", file, line, msgbuf);
criticalMsg ("The latest (NewObject()) exception's description"
" follows, to System.err:");
(*env)->ExceptionDescribe (env);
}
BADLY_BROKEN1 ("Failure of JNI NewObject()"
" to make a java.lang.RuntimeException");
- return -1;
+ retval = -1;
+ goto done;
}
@@ -480,11 +541,17 @@
that we might as well die. */
BADLY_BROKEN1
("GNU Classpath: Failure of JNI Throw to report an Exception");
- return -1;
+ retval = -1;
+ goto done;
}
DELETE_LOCAL_REF (env, wrapper);
- return 1;
+ retval = 1;
+
+ done:
+ free(msgbuf); /* NULL is OK */
+ free(bigbuf); /* NULL is OK */
+ return retval;
}
@@ -543,26 +610,29 @@
/* Like MAYBE_TROUBLE(), TROUBLE() is never used. */
#define TROUBLE(_env, _message)
\
- rethrow(_env, (*env)->ExceptionOccurred (env), _message, FALSE, \
+ rethrow (_env, (*env)->ExceptionOccurred (env), (_message), FALSE, \
__FILE__, __LINE__)
#define BROKEN(_env, _message) \
- rethrow (_env, (*env)->ExceptionOccurred (env), _message, TRUE, \
+ rethrow (_env, (*env)->ExceptionOccurred (env), (_message), TRUE, \
__FILE__, __LINE__)
/* Like MAYBE_TROUBLE(), NEW_TROUBLE() is never used. */
#define NEW_TROUBLE(_env, _message) \
- throw (_env, NULL, _message, FALSE, __FILE__, __LINE__)
+ throw (_env, NULL, (_message), FALSE, __FILE__, __LINE__)
+
+#define NEW_TROUBLE2(_env, _message, arg) \
+ throw ((_env), NULL, (_message), FALSE, __FILE__, __LINE__, (arg))
#define NEW_BROKEN(_env, _message) \
- throw (_env, NULL, _message, TRUE, __FILE__, __LINE__)
+ throw (_env, NULL, (_message), TRUE, __FILE__, __LINE__)
/* Like MAYBE_TROUBLE(), RETHROW_CAUSE() is never used. */
#define RETHROW_CAUSE(_env, _cause, _message) \
- rethrow (_env, _cause, _message, FALSE, __FILE__, __LINE__)
+ rethrow (_env, _cause, (_message), FALSE, __FILE__, __LINE__)
#define BROKEN_CAUSE(_env, _cause, _message) \
- rethrow (_env, _cause, _message, TRUE, __FILE__, __LINE__)
+ rethrow (_env, _cause, (_message), TRUE, __FILE__, __LINE__)
/* Macros to handle the possibility that someone might have called one of the
GThreadFunctions API functions with a Java exception pending. It is
@@ -575,13 +645,16 @@
1) They do not work in the C '89 subset that Classpath is currently
(2004 May 10) sticking to; HIDE_OLD_TROUBLE() includes a declaration
that should be in scope for the rest of the function, so it needs a
- language version that lets you mix declarations and statements. (This
- could be worked around if it were important.)
+ version of C (C '99, C++, or C '89 with GNU extensions) that lets you mix
+ declarations and statements. (This could be worked around if it were
+ important.)
2) They chew up more time and resources.
- 3) There does not ever seem to be old trouble -- the assertion in
- HIDE_OLD_TROUBLE never goes off.
+ 3) There is almost never old trouble -- the assertion in HIDE_OLD_TROUBLE
+ (in the commented-out form) never goes off, The exception here is that
+ glib may call private_get_jni_impl() even if mutex_unlock_jni_impl()
+ failed. The assertions *are* expensive, however.
You will want to re-enable them if this code needs to be used in a context
where old exceptions might be pending when the GThread functions are
@@ -591,18 +664,27 @@
to SHOW_OLD_TROUBLE() if they've raised exceptions during the call. So, if
we reach SHOW_OLD_TROUBLE, we are guaranteed that there are no exceptions
pending. */
-#if 1
-#define HIDE_OLD_TROUBLE(env) \
- assert ( NULL == (*env)->ExceptionOccurred (env) )
-
-#define SHOW_OLD_TROUBLE() \
- assert ( NULL == (*env)->ExceptionOccurred (env) )
-#else /* 0 */
+
+#if ENABLE_EXPENSIVE_ASSERTIONS
+
+#define HIDE_OLD_TROUBLE(env_) \
+ assert ( NULL == (*env_)->ExceptionOccurred (env_) )
+
+#define SHOW_OLD_TROUBLE(env_) \
+ assert ( NULL == (*env_)->ExceptionOccurred (env_) )
+
+#elif 1
+
+#define HIDE_OLD_TROUBLE(env_) do { } while(0)
+#define SHOW_OLD_TROUBLE(env_) do { } while(0)
+
+#else
+
#define HIDE_OLD_TROUBLE(env) \
jthrowable savedTrouble = (*env)->ExceptionOccurred (env); \
(*env)->ExceptionClear (env);
-#define SHOW_OLD_TROUBLE() do \
+#define SHOW_OLD_TROUBLE(env) do \
{ \
assert ( NULL == (*env)->ExceptionOccurred (env) ) \
if (savedTrouble) \
@@ -1181,23 +1263,26 @@
#define ENTER_MONITOR(env, m) \
enterMonitor(env, m, G_STRINGIFY(m))
-/* Return -1 on failure, 0 on success. */
+/* Lock a Java object.
+ Returns 0 on success. On failure, returns -1 and throws an exception. */
static int
enterMonitor (JNIEnv * env, jobject monitorObj, const char monName[])
{
if (TRACE_MONITORS)
tracing (" <MonitorEnter(%s)>", monName);
assert (monitorObj);
+ /* MonitorEnter() does not throw exceptions when it fails. */
if ((*env)->MonitorEnter (env, monitorObj) < 0)
{
- BROKEN (env, "cannot enter monitor");
+ NEW_TROUBLE2 (env, "trouble calling MonitorEnter(%s)", monName);
return -1;
}
return 0;
}
-/* Unlock a Java object */
+/* Unlock a Java object.
+ Returns 0 on success. On failure, returns -1 and throws an exception. */
#define EXIT_MONITOR(env, m) \
exitMonitor(env, m, G_STRINGIFY(m))
@@ -1207,9 +1292,10 @@
if (TRACE_MONITORS)
tracing (" <MonitorExit(%s)>", monName);
assert (mutexObj);
+ /* MonitorExit() normally does not throw exceptions when it fails. */
if ((*env)->MonitorExit (env, mutexObj) < 0)
{
- BROKEN (env, "cannot exit monitor ");
+ NEW_TROUBLE2 (env, "problem calling MonitorExit(%s) ", monName);
return -1;
}
return 0;
@@ -1247,6 +1333,7 @@
return thread;
}
+
/** Return the unique threadID of THREAD.
Error handling: Return (gpointer) -1 on all failures,
@@ -1272,7 +1359,7 @@
}
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
return (gpointer) threadNum;
@@ -1362,16 +1449,13 @@
if (ENTER_MONITOR (env, mcache->lockObj))
return -1;
- SHOW_OLD_TROUBLE ();
-
return 0;
}
/* Unlock a GMutex, once we're already in JNI and have already gotten the
- mutexObj for it. This skips the messages that TRACE_API_CALLS would
- print.
+ mutexObj for it.
- Returns -1 on error, 0 on success. */
+ Returns -1 on error, 0 on success. On error, throws an exception. */
static int
mutexObj_unlock (JNIEnv * env, jobject mutexObj,
struct mutexObj_cache *mcache)
@@ -1464,8 +1548,10 @@
if (populate_mutexObj_cache (env, mutexObj, &mcache) < 0)
goto done;
- mutexObj_lock (env, mutexObj, &mcache);
- /* No need to error check; we've already reported it in any case. */
+ if (mutexObj_lock (env, mutexObj, &mcache))
+ goto done;
+
+ SHOW_OLD_TROUBLE (env);
done:
clean_mutexObj_cache (env, &mcache);
@@ -1509,20 +1595,26 @@
if (potentialLockers)
{
/* Already locked. Clean up and leave. */
- EXIT_MONITOR (env, mcache.lockForPotentialLockersObj);
- /* Ignore any error code from EXIT_MONITOR; there's nothing we could do
- at this level, in any case. */
- goto done;
+ if (EXIT_MONITOR (env, mcache.lockForPotentialLockersObj) )
+ goto done;
+
+ /* We virtually ignore any error code from EXIT_MONITOR; there's nothing
+ we could do at this level, in any case. The only distinction is how
+ we handle the case of a pending exception. */
+ goto done_no_exception_pending;
}
/* Guaranteed not to block. */
if (ENTER_MONITOR (env, mcache.lockObj))
{
- /* Clean up the existing lock. */
- EXIT_MONITOR (env, mcache.lockForPotentialLockersObj);
- /* Ignore any error code from EXIT_MONITOR; there's nothing we could do
- at this level, in any case. */
- goto done;
+ /* Clean up the existing lock, if trouble. */
+ if (EXIT_MONITOR (env, mcache.lockForPotentialLockersObj) )
+ goto done;
+
+ /* We virtually ignore any error code from EXIT_MONITOR; there's nothing
+ we could do at this level, in any case. The only distinction is how
+ we handle the case of a pending exception. */
+ goto done_no_exception_pending;
}
@@ -1538,8 +1630,9 @@
if (EXIT_MONITOR (env, mcache.lockForPotentialLockersObj))
goto done; /* If we fail at this point, still keep the
main lock. */
+ done_no_exception_pending:
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
clean_mutexObj_cache (env, &mcache);
if (TRACE_API_CALLS)
@@ -1569,9 +1662,10 @@
if ( populate_mutexObj_cache (env, mutexObj, &mcache) < 0)
goto done;
- (void) mutexObj_unlock (env, mutexObj, &mcache);
+ if ( mutexObj_unlock (env, mutexObj, &mcache) < 0)
+ goto done;
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
clean_mutexObj_cache (env, &mcache);
@@ -1658,9 +1752,10 @@
goto done;
}
- EXIT_MONITOR (env, condObj);
+ if (EXIT_MONITOR (env, condObj))
+ goto done;
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
if (TRACE_API_CALLS)
@@ -1692,13 +1787,14 @@
(*env)->CallVoidMethod (env, condObj, obj_notifyall_mth);
if (MAYBE_BROKEN (env, "cannot broadcast to mutex with Object.notify()"))
{
- EXIT_MONITOR (env, condObj);
+ EXIT_MONITOR (env, condObj); /* ignore error checking; already broken */
goto done;
}
- EXIT_MONITOR (env, condObj);
+ if (EXIT_MONITOR (env, condObj))
+ goto done;
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
if (TRACE_API_CALLS)
@@ -1743,7 +1839,8 @@
(*env)->CallVoidMethod (env, condObj, obj_wait_mth);
if (MAYBE_BROKEN (env, "cannot wait on condObj"))
{
- EXIT_MONITOR (env, condObj); /* ignore err checking */
+ /* Yep, it's broken. */
+ EXIT_MONITOR (env, condObj); /* ignore err checking; already broken */
goto done;
}
@@ -1752,9 +1849,10 @@
if (mutexObj_lock (env, mutexObj, &cache))
goto done;
- EXIT_MONITOR (env, condObj);
+ if (EXIT_MONITOR (env, condObj))
+ goto done;
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
if (TRACE_API_CALLS)
@@ -1872,7 +1970,7 @@
goto done;
}
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
if (TRACE_API_CALLS)
@@ -1941,7 +2039,7 @@
}
gkey = (GPrivate *) global_key;
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
if (TRACE_API_CALLS)
@@ -1996,7 +2094,7 @@
/* Only re-raise the old pending exception if a new one hasn't come along to
supersede it. */
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
@@ -2047,7 +2145,7 @@
if (MAYBE_BROKEN (env, "cannot set thread local value"))
goto done;
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
if (TRACE_API_CALLS)
tracing (" ==> VOID\n");
@@ -2164,7 +2262,7 @@
threadID = getThreadIDFromThread (env, newThreadObj);
*(gpointer *) threadIDp = threadID;
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
if (TRACE_API_CALLS)
@@ -2190,7 +2288,7 @@
if (MAYBE_BROKEN (env, "Thread.yield() failed"))
goto done;
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
if (TRACE_API_CALLS)
@@ -2226,7 +2324,7 @@
if (MAYBE_BROKEN (env, "Thread.deRegisterJoinableThread() failed"))
goto done;
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
DELETE_LOCAL_REF (env, threadObj);
@@ -2272,7 +2370,7 @@
if (MAYBE_BROKEN (env, "cannot call Thread.stop() on current thread"))
goto done;
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
if (TRACE_API_CALLS)
@@ -2355,7 +2453,7 @@
if (threadObj_set_priority (env, threadObj, gpriority))
goto done;
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
DELETE_LOCAL_REF (env, threadObj);
@@ -2412,7 +2510,7 @@
}
my_threadID = getThreadIDFromThread (env, this_thread);
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
if (TRACE_API_CALLS)
@@ -2459,7 +2557,7 @@
goto done;
}
- SHOW_OLD_TROUBLE ();
+ SHOW_OLD_TROUBLE (env);
done:
@@ -2512,5 +2610,5 @@
"GPrivate" "GThreadFunc" "GThreadFunctions" "GThreadPriority"
"gulong"
"JNIEnv"
- "jboolean" "jclass" "jfieldID" "jint" "jlong" "jmethodID" "jobject"
"jstring" "jthrowable" ) */
+ "jboolean" "jclass" "jfieldID" "jint" "jlong" "jmethodID" "jobject"
"jstring" "jthrowable" "va_list") */
/* End: */
- gthread-jni-error-handling.patch,
Steven Augart <=