1 /* gthread-jni.c -- JNI threading routines for GLIB
2    Copyright (C) 1998, 2004 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 /************************************************************************/
39 /* Header				     				*/
40 /************************************************************************/
41 
42 /*
43  * @author Julian Dolby (dolby@us.ibm.com)
44  * @date February 7, 2003  implemented for GLIB v.1
45  *
46  *
47  * @author Steven Augart
48  * <steve+classpath at augart dot com>, <augart at watson dot ibm dot com>
49  * @date April 30, 2004 -- May 10 2004: Support new functions for Glib v.2,
50  * fix cond_wait to free and re-acquire the mutex,
51  * replaced trylock stub implementation with a full one.
52  *
53  *  This code implements the GThreadFunctions interface for GLIB using
54  * Java threading primitives.  All of the locking and conditional variable
55  * functionality required by GThreadFunctions is implemented using the
56  * monitor and wait/notify functionality of Java objects.  The thread-
57  * local functionality uses the java.lang.ThreadLocal class.
58  *
59  *  Classpath's AWT support uses GTK+ peers.  GTK+ uses GLIB.  GLIB by default
60  * uses the platform's native threading model -- pthreads in most cases.  If
61  * the Java runtime doesn't use the native threading model, then it needs this
62  * code in order to use Classpath's (GTK+-based) AWT routines.
63  *
64  *  This code should be portable; I believe it makes no assumptions
65  * about the underlying VM beyond that it implements the JNI functionality
66  * that this code uses.
67  *
68  *  Currently, use of this code is governed by the configuration option
69  * --enable-portable-native-sync.  We will soon add a VM hook so the VM can
70  * select which threading model it wants to use at run time; at that point,
71  * the configuration option will go away.
72  *
73  * The code in this file uses only JNI 1.1, except for one JNI 1.2 function:
74  * GetEnv, in the JNI Invocation API.  (There seems to be no way around using
75  * GetEnv).
76  *
77  * ACKNOWLEDGEMENT:
78  *
79  *  I would like to thank Mark Wielaard for his kindness in spending at least
80  * six hours of his own time in reviewing this code and correcting my GNU
81  * coding and commenting style.  --Steve Augart
82  *
83  *
84  * NOTES:
85  *
86  *  This code has been tested with Jikes RVM and with Kaffe.
87  *
88  *  This code should have proper automated unit tests.  I manually tested it
89  *  by running an application that uses AWT. --Steven Augart
90  *
91  * MINOR NIT:
92  *
93  *  - Using a jboolean in the arglist to "throw()" and "rethrow()"
94  *    triggers many warnings from GCC's -Wconversion operation, because that
95  *    is not the same as the conversion (upcast to an int) that would occur in
96  *    the absence of a prototype.
97  *
98  *    It would be very slightly more efficient to just pass the jboolean, but
99  *    is not worth the clutter of messages.  The right solution would be to
100  *    turn off the -Wconversion warning for just this file, *except* that
101  *    -Wconversion also warns you against constructs such as:
102  *        unsigned u = -1;
103  *    and that is a useful warning.  So I went from a "jboolean" to a
104  *    "gboolean"  (-Wconversion is not enabled by default for GNU Classpath,
105  *    but it is in my own CFLAGS, which, for gcc 3.3.3, read: -pipe -ggdb3 -W
106  *    -Wall -Wbad-function-cast -Wcast-align -Wpointer-arith -Wcast-qual
107  *    -Wshadow -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
108  *    -fkeep-static-consts -fkeep-inline-functions -Wundef -Wwrite-strings
109  *    -Wno-aggregate-return -Wmissing-noreturn -Wnested-externs -Wtrigraphs
110  *    -Wconversion -Wsign-compare -Wno-float-equal -Wmissing-format-attribute
111  *    -Wno-unreachable-code -Wdisabled-optimization )
112  */
113 
114 #include <config.h>
115 
116 /************************************************************************/
117 /* Configuration							*/
118 /************************************************************************/
119 
120 /** Tracing and Reporting  **/
121 #define TRACE_API_CALLS	    0	/* announce entry and exit into each method,
122 				   by printing to stderr. */
123 
124 #define TRACE_MONITORS      0	/* Every enterMonitor() and exitMonitor() goes
125 				   to stderr. */
126 
127 /** Trouble handling.  There is a discussion below of this.  **/
128 #define EXPLAIN_TROUBLE	    1	/* Describe any unexpected trouble that
129 				   happens.  This is a superset
130 				   of EXPLAIN_BROKEN, and if set trumps an
131 				   unset EXPLAIN_BROKEN.  It is not a strict
132 				   superset, since at the moment there is no
133 				   TROUBLE that is not also BROKEN.
134 
135 				   Use criticalMsg() to describe the problem.
136 				 */
137 
138 #define EXPLAIN_BROKEN	    1	/* Describe trouble that is serious enough to
139 				   be BROKEN.  (Right now all trouble is at
140 				   least BROKEN.) */
141 
142 /* There is no EXPLAIN_BADLY_BROKEN definition.  We always explain
143    BADLY_BROKEN trouble, since there is no other way to report it.  */
144 
145 
146 /** Error Handling  **/
147 #define DIE_IF_BROKEN	    1	/* Dies if serious trouble happens.  There is
148 				   really no non-serious trouble, except
149 				   possibly problems that arise during
150 				   pthread_create, which are reported by a
151 				   GError.
152 
153 				   If you do not set DIE_IF_BROKEN, then
154 				   trouble will raise a Java RuntimeException.
155 				   We probably do want to die right away,
156 				   since anything that's BROKEN really
157 				   indicates a programming error or a
158 				   system-wide error, and that's what the glib
159 				   documentation says you should do in case of
160 				   that kind of error in a glib-style
161 				   function.  But it does work to turn this
162 				   off.  */
163 
164 #if  DIE_IF_BROKEN
165 #define DIE_IF_BADLY_BROKEN 1	/* DIE_IF_BROKEN implies DIE_IF_BADLY_BROKEN */
166 #else
167 #define DIE_IF_BADLY_BROKEN 1	/* Die if the system is badly broken --
168 				   that is, if we have further trouble while
169 				   attempting to throw an exception
170 				   upwards, or if we are unable to generate
171 				   one of the classes we'll need in order to
172 				   throw wrapped exceptions upward.
173 
174 				   If unset, we will print a warning message,
175 				   and limp along anyway.  Not that the system
176 				   is likely to work.  */
177 #endif
178 
179 /** Performance tuning parameters **/
180 
181 #define ENABLE_EXPENSIVE_ASSERTIONS 0	/* Enable expensive assertions? */
182 
183 #define DELETE_LOCAL_REFS   1	/* Whether to delete local references.
184 
185 				   JNI only guarantees that there wil be 16
186 				   available.  (Jikes RVM provides an number
187 				   only limited by VM memory.)
188 
189 				   Jikes RVM will probably perform faster if
190 				   this is turned off, but other VMs may need
191 				   this to be turned on in order to perform at
192 				   all, or might need it if things change.
193 
194 				   Remember, we don't know how many of those
195 				   local refs might have already been used up
196 				   by higher layers of JNI code that end up
197 				   calling g_thread_self(),
198 				   g_thread_set_private(), and so on.
199 
200 				   We set this to 1 for GNU Classpath, since
201 				   one of our principles is "always go for the
202 				   most robust implementation" */
203 
204 #define  HAVE_JNI_VERSION_1_2   0 /* Assume we don't.  We could
205 				     dynamically check for this.  We will
206 				     assume JNI 1.2 in later versions of
207 				     Classpath.
208 
209                                      As it stands, the code in this file
210                                      already needs one JNI 1.2 function:
211                                      GetEnv, in the JNI Invocation API.
212 
213 				     TODO This code hasn't been tested yet.
214 				     And really hasn't been implemented yet.
215 				     */
216 
217 /************************************************************************/
218 /* Global data				     				*/
219 /************************************************************************/
220 
221 #if defined HAVE_STDINT_H
222 #include <stdint.h>		/* provides intptr_t */
223 #elif defined HAVE_INTTYPES_H
224 #include <inttypes.h>
225 #endif
226 #include <stdarg.h>		/* va_list */
227 #include <glib.h>
228 #include "gthread-jni.h"
229 #include <assert.h>		/* assert() */
230 
231 /* For Java thread priority constants. */
232 #include <gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h>
233 
234 /* Since not all JNI header generators actually define constants we
235  define them here explicitly. */
236 #ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MIN_PRIORITY
237 #define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MIN_PRIORITY 1
238 #endif
239 #ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY
240 #define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY 5
241 #endif
242 #ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY
243 #define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY 10
244 #endif
245 
246 /*  The VM handle.  This is set in
247     Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit */
248 JavaVM *cp_gtk_the_vm;
249 
250 /* Unions used for type punning. */
251 union env_union
252 {
253   void **void_env;
254   JNIEnv **jni_env;
255 };
256 
257 union func_union
258 {
259   void *void_func;
260   GThreadFunc g_func;
261 };
262 
263 /* Forward Declarations for Functions  */
264 static int threadObj_set_priority (JNIEnv * env, jobject threadObj,
265 				   GThreadPriority gpriority);
266 static void fatalMsg (const char fmt[], ...)
267      __attribute__ ((format (printf, 1, 2)))
268      __attribute__ ((noreturn));
269 
270 static void criticalMsg (const char fmt[], ...)
271      __attribute__ ((format (printf, 1, 2)));
272 
273 static void tracing (const char fmt[], ...)
274      __attribute__ ((format (printf, 1, 2)));
275 
276 static jint javaPriorityLevel (GThreadPriority priority)
277      __attribute__ ((const));
278 
279 /************************************************************************/
280 /* Trouble-handling, including utilities to reflect exceptions		*/
281 /* back to the VM.  Also some status reporting.				*/
282 /************************************************************************/
283 
284 /* How are we going to handle problems?
285 
286    There are several approaches:
287 
288    1)  Report them with the GError mechanism.
289 
290        (*thread_create)() is the only one of these functions that takes a
291        GError pointer.  And the only G_THREAD error defined maps onto EAGAIN.
292        We don't have any errors in our (*thread_create)() implementation that
293        can be mapped to EAGAIN.  So this idea is a non-starter.
294 
295    2)  Reflect the exception back to the VM, wrapped in a RuntimeException.
296        This will fail sometimes, if we're so broken (BADLY_BROKEN) that we
297        fail to throw the exception.
298 
299    3)  Abort execution.  This is what the glib functions themselves do for
300        errors that they can't report via GError.
301 
302        Enable DIE_IF_BROKEN and/or DIE_IF_BADLY_BROKEN to
303        make this the default for BROKEN and/or BADLY_BROKEN trouble.
304 
305    4) Display messages to stderr.  We always do this for BADLY_BROKEN
306       trouble.  The glib functions do that for errors they can't report via
307       GError.
308 
309    There are some complications.
310 
311    When I attempted to report a problem in g_thread_self() using g_critical (a
312    macro around g_log(), I found that g_log in turn looks for thread-private
313    data and calls g_thread_self() again.
314 
315    We got a segfault, probably due to stack overflow.  So, this code doesn't
316    use the g_critical() and g_error() functions any more.  Nor do we use
317    g_assert(); we use the C library's assert() instead.
318 */
319 
320 
321 #define WHERE __FILE__ ":" G_STRINGIFY(__LINE__) ": "
322 
323 /* This is portable to older compilers that lack variable-argument macros.
324    This used to be just g_critical(), but then we ran into the error reporting
325    problem discussed above.
326 */
327 static void
fatalMsg(const char fmt[],...)328 fatalMsg (const char fmt[], ...)
329 {
330   va_list ap;
331   va_start (ap, fmt);
332   vfprintf (stderr, fmt, ap);
333   va_end (ap);
334   fputs ("\nAborting execution\n", stderr);
335   abort ();
336 }
337 
338 
339 static void
criticalMsg(const char fmt[],...)340 criticalMsg (const char fmt[], ...)
341 {
342   va_list ap;
343   va_start (ap, fmt);
344   vfprintf (stderr, fmt, ap);
345   va_end (ap);
346   putc ('\n', stderr);
347 }
348 
349 /* Unlike the other two, this one does not append a newline.  This is only
350    used if one of the TRACE_ macros is defined.  */
351 static void
tracing(const char fmt[],...)352 tracing (const char fmt[], ...)
353 {
354   va_list ap;
355   va_start (ap, fmt);
356   vfprintf (stderr, fmt, ap);
357   va_end (ap);
358 }
359 
360 #define assert_not_reached()						\
361   do									\
362     {									\
363       fputs(WHERE "You should never get here.  Aborting execution.\n", 	\
364 	    stderr);							\
365       abort();								\
366     }									\
367   while(0)
368 
369 
370 #if DIE_IF_BADLY_BROKEN
371 #define BADLY_BROKEN fatalMsg
372 #else
373 #define BADLY_BROKEN criticalMsg
374 /* So, the user may still attempt to recover, even though we do not advise
375    this. */
376 #endif
377 
378 /* I find it so depressing to have to use C without varargs macros. */
379 #define BADLY_BROKEN_MSG WHERE "Something fundamental"		\
380 	" to GNU Classpath's AWT JNI broke while we were trying to pass up a Java error message"
381 
382 #define BADLY_BROKEN0()				\
383     BADLY_BROKEN(BADLY_BROKEN_MSG);
384 #define	    BADLY_BROKEN1(msg)			\
385     BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg)
386 #define	    BADLY_BROKEN2(msg, arg)			\
387     BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg, arg)
388 #define	    BADLY_BROKEN3(msg, arg, arg2) 		\
389     BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg, arg1, arg2)
390 #define	    BADLY_BROKEN4(msg, arg, arg2, arg3) 		\
391     BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg, arg1, arg2, arg3)
392 
393 #define DELETE_LOCAL_REF(env, ref) 		\
394   do 						\
395     {						\
396       if ( DELETE_LOCAL_REFS )			\
397 	{					\
398 	  (*env)->DeleteLocalRef (env, ref);	\
399 	  (ref) = NULL;				\
400 	}					\
401     }						\
402   while(0)
403 
404 /* Cached info for Exception-wrapping */
405 
406 static jclass runtimeException_class;	/* java.lang.RuntimeException */
407 static jmethodID runtimeException_ctor; /* constructor for it */
408 
409 
410 /* Throw a new RuntimeException.  It may wrap around an existing exception.
411    1 if we did rethrow, -1 if we had trouble while rethrowing.
412    isBroken is always true in this case. */
413 static int
throw(JNIEnv * env,jthrowable cause,const char * message,gboolean isBroken,const char * file,int line)414 throw (JNIEnv * env, jthrowable cause, const char *message,
415        gboolean isBroken, const char *file, int line)
416 {
417   jstring jmessage;
418   gboolean describedException = FALSE;	/* Did we already describe the
419 					   exception to stderr or the
420 					   equivalent?   */
421   jthrowable wrapper;
422 
423   /* allocate local message in Java */
424   const char fmt[] = "In AWT JNI, %s (at %s:%d)";
425   size_t len = strlen (message) + strlen (file) + sizeof fmt + 25;
426   char *buf;
427 
428   if (EXPLAIN_TROUBLE || (isBroken && EXPLAIN_BROKEN))
429     {
430       criticalMsg ("%s:%d: AWT JNI failure%s: %s\n", file, line,
431 		   isBroken ? " (BROKEN)" : "", message);
432       if (cause)
433 	{
434 	  jthrowable currentException = (*env)->ExceptionOccurred (env);
435 
436 	  if (cause == currentException)
437 	    {
438 	      criticalMsg ("Description follows to System.err:");
439 	      (*env)->ExceptionDescribe (env);
440 	      /* ExceptionDescribe has the side-effect of clearing the pending
441 	         exception; relaunch it.  */
442 	      describedException = TRUE;
443 
444 	      if ((*env)->Throw (env, cause))
445 		{
446 		  BADLY_BROKEN1
447 		    ("Relaunching an exception with Throw failed.");
448 		  return -1;
449 		}
450 	    }
451 	  else
452 	    {
453 	      DELETE_LOCAL_REF (env, currentException);
454 	      criticalMsg (WHERE
455 			   "currentException != cause; something else happened"
456 			   " while handling an exception.");
457 	    }
458 	}
459     }				/* if (EXPLAIN_TROUBLE) */
460 
461   if (isBroken && DIE_IF_BROKEN)
462     fatalMsg ("%s:%d: Aborting execution; BROKEN: %s\n", file, line, message);
463 
464   if ((buf = malloc (len)))
465     {
466       memset (buf, 0, len);
467       g_snprintf (buf, len, fmt, message, file, line);
468       jmessage = (*env)->NewStringUTF (env, buf);
469       free (buf);
470     }
471   else
472     {
473       jmessage = NULL;
474     }
475 
476   /* Create the RuntimeException wrapper object and throw it.  It is OK for
477      CAUSE to be NULL. */
478   wrapper = (jthrowable) (*env)->NewObject
479     (env, runtimeException_class, runtimeException_ctor, jmessage, cause);
480   DELETE_LOCAL_REF (env, jmessage);
481 
482   if (!wrapper)
483     {
484       /* I think this should only happen:
485          - if there are bugs in my JNI code, or
486          - if the VM is broken, or
487          - if we run out of memory.
488        */
489       if (EXPLAIN_TROUBLE)
490 	{
491 	  criticalMsg (WHERE "GNU Classpath: JNI NewObject() could not create"
492 		       " a new java.lang.RuntimeException.");
493 	  criticalMsg ("We were trying to warn about the following"
494 		       " previous failure:");
495 	  criticalMsg ("%s:%d: %s", file, line, message);
496 	  criticalMsg ("The latest (NewObject()) exception's description"
497 		       " follows, to System.err:");
498 	  (*env)->ExceptionDescribe (env);
499 	}
500       BADLY_BROKEN1 ("Failure of JNI NewObject()"
501 		     " to make a java.lang.RuntimeException");
502       return -1;
503     }
504 
505 
506   /* throw it */
507   if ((*env)->Throw (env, wrapper))
508     {
509       /* Throw() should just never fail, unless we're in such severe trouble
510          that we might as well die. */
511       BADLY_BROKEN1
512 	("GNU Classpath: Failure of JNI Throw to report an Exception");
513       return -1;
514     }
515 
516   DELETE_LOCAL_REF (env, wrapper);
517   return 1;
518 }
519 
520 
521 
522 /* Rethrow an exception we received, wrapping it with a RuntimeException.  1
523    if we did rethrow, -1 if we had trouble while rethrowing.
524    CAUSE should be identical to the most recent exception that happened, so
525    that ExceptionDescribe will work.  (Otherwise nix.) */
526 static int
rethrow(JNIEnv * env,jthrowable cause,const char * message,gboolean isBroken,const char * file,int line)527 rethrow (JNIEnv * env, jthrowable cause, const char *message,
528 	 gboolean isBroken, const char *file, int line)
529 {
530   assert (cause);
531   return throw (env, cause, message, isBroken, file, line);
532 }
533 
534 
535 /* This function checks for a pending exception, and rethrows it with
536  * a wrapper RuntimeException to deal with possible type problems (in
537  * case some calling piece of code does not expect the exception being
538  * thrown) and to include the given extra message.
539  *
540  * Returns 0 if no problems found (so no exception thrown), 1 if we rethrew an
541  * exception.   Returns -1 on failure.
542  */
543 static int
maybe_rethrow(JNIEnv * env,const char * message,gboolean isBroken,const char * file,int line)544 maybe_rethrow (JNIEnv * env, const char *message, gboolean isBroken,
545 	       const char *file, int line)
546 {
547   jthrowable cause = (*env)->ExceptionOccurred (env);
548   int ret = 0;
549 
550   /* rethrow if an exception happened */
551   if (cause)
552     {
553       ret = rethrow (env, cause, message, isBroken, file, line);
554       DELETE_LOCAL_REF (env, cause);
555     }
556 
557   return 0;
558 }
559 
560 /* MAYBE_TROUBLE() is used to include a source location in the exception
561    message. Once we have run maybe_rethrow, if there WAS trouble,
562    return TRUE, else FALSE.
563 
564    MAYBE_TROUBLE() is actually never used; all problems that throw exceptions
565    are BROKEN, at least.  Nothing is recoverable :(.  See the discussion of
566    possible errors at thread_create_jni_impl().  */
567 #define MAYBE_TROUBLE(_env, _message)				\
568 	maybe_rethrow(_env, _message, FALSE, __FILE__, __LINE__)
569 
570 /* MAYBE_TROUBLE(), but something would be BROKEN if it were true. */
571 #define MAYBE_BROKEN(_env, _message)				\
572 	maybe_rethrow(_env, _message, TRUE, __FILE__, __LINE__)
573 
574 /* Like MAYBE_TROUBLE(), TROUBLE() is never used. */
575 #define TROUBLE(_env, _message)						\
576 	rethrow(_env, (*env)->ExceptionOccurred (env), _message, FALSE, \
577 		__FILE__, __LINE__)
578 
579 #define BROKEN(_env, _message)						\
580 	rethrow (_env, (*env)->ExceptionOccurred (env), _message, TRUE, \
581 		 __FILE__, __LINE__)
582 
583 /* Like MAYBE_TROUBLE(), NEW_TROUBLE() is never used. */
584 #define NEW_TROUBLE(_env, _message)					\
585 	throw (_env, NULL,  _message, FALSE, __FILE__, __LINE__)
586 
587 #define NEW_BROKEN(_env, _message)				\
588 	throw (_env, NULL, _message, TRUE, __FILE__, __LINE__)
589 
590 /* Like MAYBE_TROUBLE(), RETHROW_CAUSE() is never used. */
591 #define RETHROW_CAUSE(_env, _cause, _message)				\
592 	rethrow (_env, _cause, _message, FALSE, __FILE__, __LINE__)
593 
594 #define BROKEN_CAUSE(_env, _cause, _message)				\
595 	rethrow (_env, _cause, _message, TRUE, __FILE__, __LINE__)
596 
597 /* Macros to handle the possibility that someone might have called one of the
598    GThreadFunctions API functions with a Java exception pending.  It is
599    generally discouraged to continue to use JNI after a Java exception has
600    been raised.  Sun's JNI book advises that one trap JNI errors immediately
601    and not continue with an exception pending.
602 
603    These are #if'd out for these reasons:
604 
605    1) They do not work in the C '89 subset that Classpath is currently
606       (2004 May 10) sticking to; HIDE_OLD_TROUBLE() includes a declaration
607       that should be in scope for the rest of the function, so it needs a
608       language version that lets you mix declarations and statements.  (This
609       could be worked around if it were important.)
610 
611    2) They chew up more time and resources.
612 
613    3) There does not ever seem to be old trouble -- the assertion in
614       HIDE_OLD_TROUBLE never goes off.
615 
616    You will want to re-enable them if this code needs to be used in a context
617    where old exceptions might be pending when the GThread functions are
618    called.
619 
620    The implementations in this file are responsible for skipping around calls
621    to SHOW_OLD_TROUBLE() if they've raised exceptions during the call.  So, if
622    we reach SHOW_OLD_TROUBLE, we are guaranteed that there are no exceptions
623    pending. */
624 #if 1
625 #define HIDE_OLD_TROUBLE(env)				\
626     assert ( NULL == (*env)->ExceptionOccurred (env) )
627 
628 #define SHOW_OLD_TROUBLE()	\
629     assert ( NULL == (*env)->ExceptionOccurred (env) )
630 #else  /* 0 */
631 #define HIDE_OLD_TROUBLE(env)					\
632    jthrowable savedTrouble = (*env)->ExceptionOccurred (env);	\
633    (*env)->ExceptionClear (env);
634 
635 #define SHOW_OLD_TROUBLE() do 					\
636 {								\
637   assert ( NULL == (*env)->ExceptionOccurred (env) )		\
638   if (savedTrouble) 						\
639     {								\
640       if ((*env)->Throw (env, savedTrouble)) 			\
641 	  BADLY_BROKEN ("ReThrowing the savedTrouble failed");	\
642     }								\
643   DELETE_LOCAL_REF (env, savedTrouble);				\
644 } while(0)
645 
646 #endif /* 0 */
647 
648 /* Set up the cache of jclass and jmethodID primitives we need
649    in order to throw new exceptions and rethrow exceptions.  We do this
650    independently of the other caching.  We need to have this cache set up
651    first, so that we can then report errors properly.
652 
653    If any errors while setting up the error cache, the world is BADLY_BROKEN.
654 
655    May be called more than once.
656 
657    Returns -1 if the cache was not initialized properly, 1 if it was.
658 */
659 static int
setup_exception_cache(JNIEnv * env)660 setup_exception_cache (JNIEnv * env)
661 {
662   static int exception_cache_initialized = 0;	/* -1 for trouble, 1 for proper
663 						   init.  */
664 
665   jclass lcl_class;		/* a class used for local refs */
666 
667   if (exception_cache_initialized)
668     return exception_cache_initialized;
669   lcl_class = (*env)->FindClass (env, "java/lang/RuntimeException");
670   if ( ! lcl_class )
671     {
672       BADLY_BROKEN1 ("Broken Class library or VM?"
673 		     "  Couldn't find java/lang/RuntimeException");
674       return exception_cache_initialized = -1;
675     }
676   /* Pin it down. */
677   runtimeException_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
678   DELETE_LOCAL_REF (env, lcl_class);
679   if (!runtimeException_class)
680     {
681       BADLY_BROKEN1 ("Serious trouble: could not turn"
682 		     " java.lang.RuntimeException into a global reference");
683       return exception_cache_initialized = -1;
684     }
685 
686   runtimeException_ctor =
687     (*env)->GetMethodID (env, runtimeException_class, "<init>",
688 			   "(Ljava/lang/String;Ljava/lang/Throwable;)V");
689   if ( ! runtimeException_ctor )
690     {
691       BADLY_BROKEN1 ("Serious trouble: classpath couldn't find a"
692 		     " two-arg constructor for java/lang/RuntimeException");
693       return exception_cache_initialized = -1;
694     }
695 
696   return exception_cache_initialized = 1;
697 }
698 
699 
700 /**********************************************************/
701 /***** The main cache *************************************/
702 /**********************************************************/
703 
704 /** This is a cache of all classes, methods, and field IDs that we use during
705    the run.  We maintain a permanent global reference to each of the classes
706    we cache, since otherwise the (local) jclass that refers to that class
707    would go out of scope and possibly be reused in further calls.
708 
709    The permanent global reference also achieves the secondary goal of
710    protecting the validity of the methods and field IDs in case the classes
711    were otherwise unloaded and then later loaded again.  Obviously, this will
712    never happen to classes such as java.lang.Thread and java.lang.Object, but
713    the primary reason for maintaining permanent global refs is sitll valid.
714 
715    The code in jnilink.c has a similar objective.  TODO: Consider using that
716    code instead.
717 
718    --Steven Augart
719 */
720 
721 /* All of these are cached classes and method IDs: */
722 /* java.lang.Object */
723 static jclass obj_class;		/* java.lang.Object */
724 static jmethodID obj_ctor;		/* no-arg Constructor for java.lang.Object */
725 static jmethodID obj_notify_mth;	/* java.lang.Object.notify() */
726 static jmethodID obj_notifyall_mth;	/* java.lang.Object.notifyall() */
727 static jmethodID obj_wait_mth;		/* java.lang.Object.wait() */
728 static jmethodID obj_wait_nanotime_mth; /* java.lang.Object.wait(JI) */
729 
730 /* GThreadMutex and its methods */
731 static jclass mutex_class;
732 static jmethodID mutex_ctor;
733 static jfieldID mutex_lockForPotentialLockers_fld;
734 static jfieldID mutex_potentialLockers_fld;
735 
736 /* java.lang.Thread and its methods*/
737 static jclass thread_class;		/* java.lang.Thread */
738 static jmethodID thread_current_mth;	/* Thread.currentThread() */
739 static jmethodID thread_equals_mth;	/* Thread.equals() */
740 static jmethodID thread_join_mth;	/* Thread.join() */
741 static jmethodID thread_setPriority_mth; /* Thread.setPriority() */
742 static jmethodID thread_stop_mth;	/* Thread.stop() */
743 static jmethodID thread_yield_mth;	/* Thread.yield() */
744 
745 /* java.lang.ThreadLocal and its methods */
746 static jclass threadlocal_class;	/* java.lang.ThreadLocal */
747 static jmethodID threadlocal_ctor;	/* Its constructor */
748 static jmethodID threadlocal_set_mth;	/* ThreadLocal.set() */
749 static jmethodID threadlocal_get_mth;	/* ThreadLocal.get() */
750 
751 /* java.lang.Long and its methods */
752 static jclass long_class;		/* java.lang.Long */
753 static jmethodID long_ctor;		/* constructor for it: (J) */
754 static jmethodID long_longValue_mth;	/* longValue()J */
755 
756 
757 /* GThreadNativeMethodRunner */
758 static jclass runner_class;
759 static jmethodID runner_ctor;
760 static jmethodID runner_threadToThreadID_mth;
761 static jmethodID runner_threadIDToThread_mth;
762 static jmethodID runner_deRegisterJoinable_mth;
763 static jmethodID runner_start_mth;	/* Inherited Thread.start() */
764 
765 
766 /* java.lang.InterruptedException */
767 static jclass interrupted_exception_class;
768 
769 
770 
771 
772 /* Returns a negative value if there was trouble during initialization.
773    Returns a positive value of the cache was initialized correctly.
774    Never returns zero. */
775 static int
setup_cache(JNIEnv * env)776 setup_cache (JNIEnv * env)
777 {
778   jclass lcl_class;
779   static int initialized = 0;	/* 1 means initialized, 0 means uninitialized,
780 				   -1 means mis-initialized */
781 
782   if (initialized)
783     return initialized;
784 
785   /* make sure we can report on trouble */
786   if (setup_exception_cache (env) < 0)
787     return initialized = -1;
788 
789 #ifdef JNI_VERSION_1_2
790   if (HAVE_JNI_VERSION_1_2)
791     assert ( ! (*env)->ExceptionCheck (env));
792   else
793 #endif
794     assert ( ! (*env)->ExceptionOccurred (env));
795 
796   /* java.lang.Object and its methods */
797   lcl_class = (*env)->FindClass (env, "java/lang/Object");
798   if (!lcl_class)
799     {
800       BROKEN (env, "cannot find java.lang.Object");
801       return initialized = -1;
802     }
803 
804   /* Pin it down. */
805   obj_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
806   DELETE_LOCAL_REF (env, lcl_class);
807   if (!obj_class)
808     {
809       BROKEN (env, "Cannot get a global reference to java.lang.Object");
810       return initialized = -1;
811     }
812 
813   obj_ctor = (*env)->GetMethodID (env, obj_class, "<init>", "()V");
814   if (!obj_ctor)
815     {
816       BROKEN (env, "cannot find constructor for java.lang.Object");
817       return initialized = -1;
818     }
819 
820   obj_notify_mth = (*env)->GetMethodID (env, obj_class, "notify", "()V");
821   if ( ! obj_notify_mth )
822     {
823       BROKEN (env, "cannot find java.lang.Object.notify()V");
824       return initialized = -1;
825     }
826 
827   obj_notifyall_mth =
828     (*env)->GetMethodID (env, obj_class, "notifyAll", "()V");
829   if ( ! obj_notifyall_mth)
830     {
831       BROKEN (env, "cannot find java.lang.Object.notifyall()V");
832       return initialized = -1;
833     }
834 
835   obj_wait_mth = (*env)->GetMethodID (env, obj_class, "wait", "()V");
836   if ( ! obj_wait_mth )
837     {
838       BROKEN (env, "cannot find Object.<wait()V>");
839       return initialized = -1;
840     }
841 
842   obj_wait_nanotime_mth =
843     (*env)->GetMethodID (env, obj_class, "wait", "(JI)V");
844   if ( ! obj_wait_nanotime_mth )
845     {
846       BROKEN (env, "cannot find Object.<wait(JI)V>");
847       return initialized = -1;
848     }
849 
850   /* GThreadMutex and its methods */
851   lcl_class = (*env)->FindClass (env, "gnu/java/awt/peer/gtk/GThreadMutex");
852   if ( ! lcl_class)
853     {
854       BROKEN (env, "cannot find gnu.java.awt.peer.gtk.GThreadMutex");
855       return initialized = -1;
856     }
857   /* Pin it down. */
858   mutex_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
859   DELETE_LOCAL_REF (env, lcl_class);
860   if ( ! mutex_class)
861     {
862       BROKEN (env, "Cannot get a global reference to GThreadMutex");
863       return initialized = -1;
864     }
865 
866   mutex_ctor = (*env)->GetMethodID (env, mutex_class, "<init>", "()V");
867   if ( ! mutex_ctor)
868     {
869       BROKEN (env, "cannot find zero-arg constructor for GThreadMutex");
870       return initialized = -1;
871     }
872 
873   mutex_potentialLockers_fld = (*env)->GetFieldID
874     (env, mutex_class, "potentialLockers", "I");
875   if ( ! mutex_class )
876     {
877       BROKEN (env, "cannot find GThreadMutex.potentialLockers");
878       return initialized = -1;
879     }
880 
881   if (! (mutex_lockForPotentialLockers_fld = (*env)->GetFieldID
882 	 (env, mutex_class, "lockForPotentialLockers", "Ljava/lang/Object;")))
883     {
884       BROKEN (env, "cannot find GThreadMutex.lockForPotentialLockers");
885       return initialized = -1;
886     }
887 
888 
889   /* java.lang.Thread */
890   if (! (lcl_class = (*env)->FindClass (env, "java/lang/Thread")))
891     {
892       BROKEN (env, "cannot find java.lang.Thread");
893       return initialized = -1;
894     }
895 
896   /* Pin it down. */
897   thread_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
898   DELETE_LOCAL_REF (env, lcl_class);
899   if (!thread_class)
900     {
901       BROKEN (env, "Cannot get a global reference to java.lang.Thread");
902       return initialized = -1;
903     }
904 
905   thread_current_mth =
906     (*env)->GetStaticMethodID (env, thread_class, "currentThread",
907 			       "()Ljava/lang/Thread;");
908   if (!thread_current_mth)
909     {
910       BROKEN (env, "cannot find Thread.currentThread() method");
911       return initialized = -1;
912     }
913 
914   thread_equals_mth =
915     (*env)->GetMethodID (env, thread_class, "equals", "(Ljava/lang/Object;)Z");
916   if (!thread_equals_mth)
917     {
918       BROKEN (env, "cannot find Thread.equals() method");
919       return initialized = -1;
920     }
921 
922   thread_join_mth = (*env)->GetMethodID (env, thread_class, "join", "()V");
923   if (!thread_join_mth)
924     {
925       BROKEN (env, "cannot find Thread.join() method");
926       return initialized = -1;
927     }
928 
929   thread_stop_mth = (*env)->GetMethodID (env, thread_class, "stop", "()V");
930   if ( ! thread_stop_mth )
931     {
932       BROKEN (env, "cannot find Thread.stop() method");
933       return initialized = -1;
934     }
935 
936   thread_setPriority_mth =
937     (*env)->GetMethodID (env, thread_class, "setPriority", "(I)V");
938   if ( ! thread_setPriority_mth )
939     {
940       BROKEN (env, "cannot find Thread.setPriority() method");
941       return initialized = -1;
942     }
943 
944   thread_yield_mth =
945     (*env)->GetStaticMethodID (env, thread_class, "yield", "()V");
946   if ( ! thread_yield_mth )
947     {
948       BROKEN (env, "cannot find Thread.yield() method");
949       return initialized = -1;
950     }
951 
952   /* java.lang.ThreadLocal */
953   lcl_class = (*env)->FindClass (env, "java/lang/ThreadLocal");
954   if ( ! lcl_class )
955     {
956       BROKEN (env, "cannot find class java.lang.ThreadLocal");
957       return initialized = -1;
958     }
959 
960   /* Pin it down. */
961   threadlocal_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
962   DELETE_LOCAL_REF (env, lcl_class);
963   if ( ! threadlocal_class )
964     {
965       BROKEN (env, "Cannot get a global reference to java.lang.ThreadLocal");
966       return initialized = -1;
967     }
968 
969   threadlocal_ctor = (*env)->GetMethodID (env, threadlocal_class,
970                                           "<init>", "()V");
971   if ( ! threadlocal_ctor )
972     {
973       BROKEN (env, "cannot find ThreadLocal.<init>()V");
974       return initialized = -1;
975     }
976 
977   threadlocal_get_mth = (*env)->GetMethodID (env, threadlocal_class,
978                                              "get", "()Ljava/lang/Object;");
979   if ( ! threadlocal_get_mth )
980     {
981       BROKEN (env, "cannot find java.lang.ThreadLocal.get()Object");
982       return initialized = -1;
983     }
984 
985   threadlocal_set_mth = (*env)->GetMethodID (env, threadlocal_class,
986                                              "set", "(Ljava/lang/Object;)V");
987   if ( ! threadlocal_set_mth )
988     {
989       BROKEN (env, "cannot find ThreadLocal.set(Object)V");
990       return initialized = -1;
991     }
992 
993   /* java.lang.Long */
994   lcl_class = (*env)->FindClass (env, "java/lang/Long");
995   if ( ! lcl_class )
996     {
997       BROKEN (env, "cannot find class java.lang.Long");
998       return initialized = -1;
999     }
1000 
1001   /* Pin it down. */
1002   long_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
1003   DELETE_LOCAL_REF (env, lcl_class);
1004   if (!long_class)
1005     {
1006       BROKEN (env, "Cannot get a global reference to java.lang.Long");
1007       return initialized = -1;
1008     }
1009 
1010   long_ctor = (*env)->GetMethodID (env, long_class, "<init>", "(J)V");
1011   if (!long_ctor)
1012     {
1013       BROKEN (env, "cannot find method java.lang.Long.<init>(J)V");
1014       return initialized = -1;
1015     }
1016 
1017   long_longValue_mth =
1018     (*env)->GetMethodID (env, long_class, "longValue", "()J");
1019   if (!long_longValue_mth)
1020     {
1021       BROKEN (env, "cannot find method java.lang.Long.longValue()J");
1022       return initialized = -1;
1023     }
1024 
1025 
1026   /* GThreadNativeMethodRunner */
1027   lcl_class =
1028     (*env)->FindClass (env,
1029                        "gnu/java/awt/peer/gtk/GThreadNativeMethodRunner");
1030   if ( ! lcl_class )
1031     {
1032       BROKEN (env,
1033 	      "cannot find gnu.java.awt.peer.gtk.GThreadNativeMethodRunner");
1034       return initialized = -1;
1035     }
1036 
1037   /* Pin it down. */
1038   runner_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
1039   DELETE_LOCAL_REF (env, lcl_class);
1040   if (!runner_class)
1041     {
1042       BROKEN (env,
1043 	      "Cannot get a global reference to the class GThreadNativeMethodRunner");
1044       return initialized = -1;
1045     }
1046 
1047   runner_ctor = (*env)->GetMethodID (env, runner_class, "<init>", "(JJZ)V");
1048   if ( ! runner_ctor )
1049     {
1050       BROKEN (env,
1051 	      "cannot find method GThreadNativeMethodRunner.<init>(JJZ)");
1052       return initialized = -1;
1053     }
1054 
1055   runner_start_mth = (*env)->GetMethodID (env, runner_class, "start", "()V");
1056   if ( ! runner_start_mth )
1057     {
1058       BROKEN (env, "cannot find method GThreadNativeMethodRunner.start()V");
1059       return initialized = -1;
1060     }
1061 
1062 
1063   runner_threadToThreadID_mth =
1064     (*env)->GetStaticMethodID (env, runner_class,
1065                                "threadToThreadID", "(Ljava/lang/Thread;)I");
1066   if ( ! runner_threadToThreadID_mth )
1067     {
1068       BROKEN (env,
1069 	      "cannot find method GThreadNativeMethodRunner.threadToThreadID(java.lang.Thread)I");
1070       return initialized = -1;
1071     }
1072 
1073 
1074   runner_threadIDToThread_mth =
1075     (*env)->GetStaticMethodID (env, runner_class,
1076                                "threadIDToThread", "(I)Ljava/lang/Thread;");
1077   if ( ! runner_threadIDToThread_mth )
1078     {
1079       BROKEN (env,
1080 	      "cannot find method GThreadNativeMethodRunner.threadIDToThread(I)java.lang.Thread");
1081       return initialized = -1;
1082     }
1083 
1084 
1085   runner_deRegisterJoinable_mth =
1086     (*env)->GetStaticMethodID (env, runner_class, "deRegisterJoinable",
1087 			       "(Ljava/lang/Thread;)V");
1088   if (!runner_deRegisterJoinable_mth)
1089     {
1090       BROKEN (env,
1091 	      "cannot find method GThreadNativeMethodRunner.deRegisterJoinable(java.lang.Thread)V");
1092       return initialized = -1;
1093     }
1094 
1095 
1096   /* java.lang.InterruptedException */
1097   lcl_class = (*env)->FindClass (env, "java/lang/InterruptedException");
1098   if ( ! lcl_class )
1099     {
1100       BROKEN (env, "cannot find class java.lang.InterruptedException");
1101       return initialized = -1;
1102     }
1103 
1104   /* Pin it down. */
1105   interrupted_exception_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
1106   DELETE_LOCAL_REF (env, lcl_class);
1107   if (!interrupted_exception_class)
1108     {
1109       BROKEN (env, "Cannot make a global reference"
1110 	      " to java.lang.InterruptedException");
1111       return initialized = -1;
1112     }
1113 
1114 #ifdef JNI_VERSION_1_2
1115   if (HAVE_JNI_VERSION_1_2)
1116     assert ( ! (*env)->ExceptionCheck (env));
1117   else
1118 #endif
1119     assert ( ! (*env)->ExceptionOccurred (env));
1120 
1121 
1122   return initialized = 1;
1123 }
1124 
1125 
1126 
1127 
1128 
1129 /************************************************************************/
1130 /* Utilities to allocate and free java.lang.Objects			*/
1131 /************************************************************************/
1132 
1133 /* The condition variables are java.lang.Object objects,
1134  * which this method allocates and returns a global ref.  Note that global
1135  * refs must be explicitly freed (isn't C fun?).
1136  */
1137 static jobject
allocatePlainObject(JNIEnv * env)1138 allocatePlainObject (JNIEnv * env)
1139 {
1140   jobject lcl_obj, global_obj;
1141 
1142   lcl_obj = (*env)->NewObject (env, obj_class, obj_ctor);
1143   if (!lcl_obj)
1144     {
1145       BROKEN (env, "cannot allocate object");
1146       return NULL;
1147     }
1148 
1149   global_obj = (*env)->NewGlobalRef (env, lcl_obj);
1150   DELETE_LOCAL_REF (env, lcl_obj);
1151   if (!global_obj)
1152     {
1153       NEW_BROKEN (env, "cannot make global ref for a new plain Java object");
1154       /* Deliberate fall-through */
1155     }
1156 
1157   return global_obj;
1158 }
1159 
1160 /*  Frees any Java object given a global ref (isn't C fun?) */
1161 static void
freeObject(JNIEnv * env,jobject obj)1162 freeObject (JNIEnv * env, jobject obj)
1163 {
1164   if (obj)
1165     {
1166       (*env)->DeleteGlobalRef (env, obj);
1167       /* DeleteGlobalRef can never fail */
1168     }
1169 }
1170 
1171 
1172 /************************************************************************/
1173 /* Utilities to allocate and free Java mutexes				*/
1174 /************************************************************************/
1175 
1176 /* The mutexes are gnu.java.awt.peer.gtk.GThreadMutex objects,
1177  * which this method allocates and returns a global ref.  Note that global
1178  * refs must be explicitly freed (isn't C fun?).
1179  *
1180  * Free this with freeObject()
1181  */
1182 static jobject
allocateMutexObject(JNIEnv * env)1183 allocateMutexObject (JNIEnv * env)
1184 {
1185   jobject lcl_obj, global_obj;
1186 
1187   lcl_obj = (*env)->NewObject (env, mutex_class, mutex_ctor);
1188   if (!lcl_obj)
1189     {
1190       BROKEN (env, "cannot allocate a GThreadMutex");
1191       return NULL;
1192     }
1193 
1194   global_obj = (*env)->NewGlobalRef (env, lcl_obj);
1195   DELETE_LOCAL_REF (env, lcl_obj);
1196   if (!global_obj)
1197     {
1198       NEW_BROKEN (env, "cannot make global ref");
1199       /* Deliberate fallthrough */
1200     }
1201 
1202   return global_obj;
1203 }
1204 
1205 
1206 /************************************************************************/
1207 /* Locking code				     				*/
1208 /************************************************************************/
1209 
1210 /* Lock a Java object */
1211 #define ENTER_MONITOR(env, m)			\
1212     enterMonitor(env, m, G_STRINGIFY(m))
1213 
1214 /* Return -1 on failure, 0 on success. */
1215 static int
enterMonitor(JNIEnv * env,jobject monitorObj,const char monName[])1216 enterMonitor (JNIEnv * env, jobject monitorObj, const char monName[])
1217 {
1218   if (TRACE_MONITORS)
1219     tracing ("  <MonitorEnter(%s)>", monName);
1220   assert (monitorObj);
1221   if ((*env)->MonitorEnter (env, monitorObj) < 0)
1222     {
1223       BROKEN (env, "cannot enter monitor");
1224       return -1;
1225     }
1226   return 0;
1227 }
1228 
1229 
1230 /* Unlock a Java object */
1231 #define EXIT_MONITOR(env, m)			\
1232     exitMonitor(env, m, G_STRINGIFY(m))
1233 
1234 static int
exitMonitor(JNIEnv * env,jobject mutexObj,const char monName[])1235 exitMonitor (JNIEnv * env, jobject mutexObj, const char monName[])
1236 {
1237   if (TRACE_MONITORS)
1238     tracing (" <MonitorExit(%s)>", monName);
1239   assert (mutexObj);
1240   if ((*env)->MonitorExit (env, mutexObj) < 0)
1241     {
1242       BROKEN (env, "cannot exit monitor ");
1243       return -1;
1244     }
1245   return 0;
1246 }
1247 
1248 
1249 /************************************************************************/
1250 /* Miscellaneous utilities		     				*/
1251 /************************************************************************/
1252 
1253 /* Get the Java Thread object that corresponds to a particular thread ID.
1254    A negative thread Id gives us a null object.
1255 
1256    Returns a local reference.
1257 */
1258 static jobject
getThreadFromThreadID(JNIEnv * env,gpointer gThreadID)1259 getThreadFromThreadID (JNIEnv * env, gpointer gThreadID)
1260 {
1261   jint threadNum = (jint) gThreadID;
1262   jobject thread;
1263 
1264   if (threadNum < 0)
1265     {
1266       NEW_BROKEN (env, "getThreadFromThreadID asked to look up"
1267 		       " a negative thread index");
1268       return NULL;
1269     }
1270 
1271   thread = (*env)->CallStaticObjectMethod
1272     (env, runner_class, runner_threadIDToThread_mth, threadNum);
1273 
1274   if (MAYBE_BROKEN (env, "cannot get Thread for threadID "))
1275     return NULL;
1276 
1277   return thread;
1278 }
1279 
1280 /** Return the unique threadID of THREAD.
1281 
1282    Error handling: Return (gpointer) -1 on all failures,
1283    and propagate an exception.
1284 */
1285 static gpointer
getThreadIDFromThread(JNIEnv * env,jobject thread)1286 getThreadIDFromThread (JNIEnv * env, jobject thread)
1287 {
1288   jint threadNum;
1289 
1290   if (ENABLE_EXPENSIVE_ASSERTIONS)
1291     assert ((*env)->IsInstanceOf (env, thread, thread_class));
1292 
1293   HIDE_OLD_TROUBLE (env);
1294 
1295   threadNum = (*env)->CallStaticIntMethod
1296     (env, runner_class, runner_threadToThreadID_mth, thread);
1297 
1298   if (MAYBE_BROKEN (env, "cannot get ThreadID for a Thread "))
1299     {
1300       threadNum = -1;
1301       goto done;
1302     }
1303 
1304 
1305   SHOW_OLD_TROUBLE ();
1306 
1307 done:
1308   return (gpointer) threadNum;
1309 }
1310 
1311 
1312 /************************************************************************/
1313 /* The Actual JNI functions that we pass to the function vector.	*/
1314 /************************************************************************/
1315 
1316 
1317 /************************************************************************/
1318 /* Mutex Functions                                                  	*/
1319 /************************************************************************/
1320 
1321 /*** Mutex Utilities  ****/
1322 struct mutexObj_cache
1323 {
1324   jobject lockForPotentialLockersObj;	/* Lock for the potentialLockers
1325 					   field.  Local reference. */
1326   jobject lockObj;		/* The real lock we use.  This is a GLOBAL
1327 				   reference and must not be freed. */
1328 };
1329 
1330 /* Initialize the cache of sub-locks for a particular mutex object.
1331 
1332   -1 on error, 0 on success.  The caller is not responsible for freeing the
1333    partially-populated cache in case of failure (but in practice does anyway)
1334    (This actually never fails, though, since GetObjectField allegedly never
1335    fails.)
1336 
1337    Guaranteed to leave all fields of the cache initialized, even if only to
1338    zero.
1339 */
1340 static int
populate_mutexObj_cache(JNIEnv * env,jobject mutexObj,struct mutexObj_cache * mcache)1341 populate_mutexObj_cache (JNIEnv * env, jobject mutexObj,
1342 			 struct mutexObj_cache *mcache)
1343 {
1344   mcache->lockObj = mutexObj;	/* the mutexObj is its own lock.  */
1345   assert (mcache->lockObj);
1346 
1347   mcache->lockForPotentialLockersObj = (*env)->GetObjectField
1348     (env, mutexObj, mutex_lockForPotentialLockers_fld);
1349   /* GetObjectField can never fail. */
1350 
1351   /*  Retrieving a NULL object could only happen if we somehow got a
1352       a mutex object that was not properly intialized. */
1353   assert (mcache->lockForPotentialLockersObj);
1354 
1355   return 0;
1356 }
1357 
1358 
1359 /* Clean out the mutexObj_cache, even if it was never populated. */
1360 static void
clean_mutexObj_cache(JNIEnv * env,struct mutexObj_cache * mcache)1361 clean_mutexObj_cache (JNIEnv * env, struct mutexObj_cache *mcache)
1362 {
1363   /* OK to pass NULL refs to DELETE_LOCAL_REF */
1364   DELETE_LOCAL_REF (env, mcache->lockForPotentialLockersObj);
1365   /* mcache->lockObj is a GLOBAL reference. */
1366   mcache->lockObj = NULL;
1367 }
1368 
1369 /* -1 on failure, 0 on success.
1370    The mutexObj_cache is already populated for this particular object. */
1371 static int
mutexObj_lock(JNIEnv * env,jobject mutexObj,struct mutexObj_cache * mcache)1372 mutexObj_lock (JNIEnv * env, jobject mutexObj, struct mutexObj_cache *mcache)
1373 {
1374   jint potentialLockers;
1375 
1376   if (ENTER_MONITOR (env, mcache->lockForPotentialLockersObj))
1377     return -1;
1378 
1379   assert(mutexObj);
1380   potentialLockers =
1381     (*env)->GetIntField (env, mutexObj, mutex_potentialLockers_fld);
1382   /* GetIntField() never fails. */
1383 
1384   ++potentialLockers;
1385 
1386   (*env)->SetIntField
1387     (env, mutexObj, mutex_potentialLockers_fld, potentialLockers);
1388 
1389   if (EXIT_MONITOR (env, mcache->lockForPotentialLockersObj))
1390     return -1;
1391 
1392   if (ENTER_MONITOR (env, mcache->lockObj))
1393     return -1;
1394 
1395   SHOW_OLD_TROUBLE ();
1396 
1397   return 0;
1398 }
1399 
1400 /* Unlock a GMutex, once we're already in JNI and have already gotten the
1401    mutexObj for it.  This skips the messages that TRACE_API_CALLS would
1402    print.
1403 
1404    Returns -1 on error, 0 on success. */
1405 static int
mutexObj_unlock(JNIEnv * env,jobject mutexObj,struct mutexObj_cache * mcache)1406 mutexObj_unlock (JNIEnv * env, jobject mutexObj,
1407 		 struct mutexObj_cache *mcache)
1408 {
1409   jint potentialLockers;
1410   int ret = -1;			/* assume failure until we suceed.  */
1411 
1412   /* Free the lock first, so that someone waiting for the lock can get it
1413      ASAP. */
1414   /* This is guaranteed not to block. */
1415   if (EXIT_MONITOR (env, mcache->lockObj) < 0)
1416     goto done;
1417 
1418   /* Kick down potentialLockers by one.  We do this AFTER we free the lock, so
1419      that we hold it no longer than necessary. */
1420   if (ENTER_MONITOR (env, mcache->lockForPotentialLockersObj) < 0)
1421     goto done;
1422 
1423   potentialLockers = (*env)->GetIntField
1424     (env, mutexObj, mutex_potentialLockers_fld);
1425   /* GetIntField never fails */
1426 
1427   assert (potentialLockers >= 1);
1428   --potentialLockers;
1429 
1430   (*env)->SetIntField
1431     (env, mutexObj, mutex_potentialLockers_fld, potentialLockers);
1432   /* Never fails, so the JNI book says. */
1433 
1434   /* Clean up. */
1435   if (EXIT_MONITOR (env, mcache->lockForPotentialLockersObj) < 0)
1436     goto done;
1437   ret = 0;
1438 
1439 done:
1440   return ret;
1441 }
1442 
1443 /*** Mutex Implementations ****/
1444 
1445 /* Create a mutex, which is a java.lang.Object for us.
1446    In case of failure, we'll return NULL.  Which will implicitly
1447    cause future calls to fail. */
1448 static GMutex *
mutex_new_jni_impl(void)1449 mutex_new_jni_impl (void)
1450 {
1451   jobject mutexObj;
1452   JNIEnv *env;
1453   union env_union e;
1454 
1455   if (TRACE_API_CALLS)
1456     tracing ("mutex_new_jni_impl()");
1457 
1458   e.jni_env = &env;
1459   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
1460 
1461   if (setup_cache (env) < 0)
1462     {
1463       mutexObj = NULL;
1464       goto done;
1465     }
1466 
1467   mutexObj = allocateMutexObject (env);
1468 
1469 done:
1470   if (TRACE_API_CALLS)
1471     tracing (" ==> %p \n", mutexObj);
1472 
1473   return (GMutex *) mutexObj;
1474 
1475 }
1476 
1477 /* Lock a mutex. */
1478 static void
mutex_lock_jni_impl(GMutex * mutex)1479 mutex_lock_jni_impl (GMutex * mutex)
1480 {
1481   struct mutexObj_cache mcache;
1482   jobject mutexObj = (jobject) mutex;
1483   JNIEnv *env;
1484   union env_union e;
1485 
1486   if (TRACE_API_CALLS)
1487     tracing ("mutex_lock_jni_impl( mutexObj = %p )", mutexObj);
1488 
1489   assert (mutexObj);
1490   e.jni_env = &env;
1491   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
1492 
1493   if (setup_cache (env) < 0)
1494     goto done;
1495 
1496   HIDE_OLD_TROUBLE (env);
1497 
1498   if (populate_mutexObj_cache (env, mutexObj, &mcache) < 0)
1499     goto done;
1500 
1501   mutexObj_lock (env, mutexObj, &mcache);
1502   /* No need to error check; we've already reported it in any case. */
1503 
1504 done:
1505   clean_mutexObj_cache (env, &mcache);
1506   if (TRACE_API_CALLS)
1507     tracing (" ==> VOID \n");
1508 }
1509 
1510 
1511 /*  Try to lock a mutex.  Return TRUE if we succeed, FALSE if we fail.
1512     FALSE on error. */
1513 static gboolean
mutex_trylock_jni_impl(GMutex * gmutex)1514 mutex_trylock_jni_impl (GMutex * gmutex)
1515 {
1516   jobject mutexObj = (jobject) gmutex;
1517   jint potentialLockers;
1518   gboolean ret = FALSE;
1519   JNIEnv *env;
1520   union env_union e;
1521   struct mutexObj_cache mcache;
1522 
1523   if (TRACE_API_CALLS)
1524     tracing ("mutex_trylock_jni_impl(mutexObj=%p)", mutexObj);
1525 
1526   assert (mutexObj);
1527 
1528   e.jni_env = &env;
1529   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
1530   if (setup_cache (env) < 0)
1531     goto done;
1532   HIDE_OLD_TROUBLE (env);
1533 
1534   if (populate_mutexObj_cache (env, mutexObj, &mcache) < 0)
1535     goto done;
1536 
1537   if (ENTER_MONITOR (env, mcache.lockForPotentialLockersObj))
1538     goto done;
1539 
1540   potentialLockers = (*env)->GetIntField
1541     (env, mutexObj, mutex_potentialLockers_fld);
1542 
1543   assert (potentialLockers >= 0);
1544 
1545   if (potentialLockers)
1546     {
1547       /* Already locked.  Clean up and leave. */
1548       EXIT_MONITOR (env, mcache.lockForPotentialLockersObj);
1549       /* Ignore any error code from EXIT_MONITOR; there's nothing we could do
1550 	 at this level, in any case. */
1551       goto done;
1552     }
1553 
1554   /* Guaranteed not to block. */
1555   if (ENTER_MONITOR (env, mcache.lockObj))
1556     {
1557       /* Clean up the existing lock. */
1558       EXIT_MONITOR (env, mcache.lockForPotentialLockersObj);
1559       /* Ignore any error code from EXIT_MONITOR; there's nothing we could do
1560 	 at this level, in any case. */
1561       goto done;
1562     }
1563 
1564 
1565   /* We have the monitor.  Record that fact. */
1566   potentialLockers = 1;
1567   (*env)->SetIntField
1568     (env, mutexObj, mutex_potentialLockers_fld, potentialLockers);
1569   /* Set*Field() never fails */
1570 
1571   ret = TRUE;			/* We have the lock. */
1572 
1573   /* Clean up. */
1574   if (EXIT_MONITOR (env, mcache.lockForPotentialLockersObj))
1575       goto done;		/* If we fail at this point, still keep the
1576 				   main lock.  */
1577 
1578   SHOW_OLD_TROUBLE ();
1579 done:
1580   clean_mutexObj_cache (env, &mcache);
1581   if (TRACE_API_CALLS)
1582     tracing (" ==> %s\n", ret ? "TRUE" : "FALSE");
1583   return ret;
1584 }
1585 
1586 
1587 /* Unlock a mutex. */
1588 static void
mutex_unlock_jni_impl(GMutex * gmutex)1589 mutex_unlock_jni_impl (GMutex * gmutex)
1590 {
1591   jobject mutexObj = (jobject) gmutex;
1592   struct mutexObj_cache mcache;
1593   JNIEnv *env;
1594   union env_union e;
1595 
1596   if (TRACE_API_CALLS)
1597     tracing ("mutex_unlock_jni_impl(mutexObj=%p)", mutexObj);
1598 
1599   e.jni_env = &env;
1600   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
1601   if (setup_cache (env) < 0)
1602     goto done;
1603   HIDE_OLD_TROUBLE (env);
1604 
1605   assert (mutexObj);
1606 
1607   if ( populate_mutexObj_cache (env, mutexObj, &mcache) < 0)
1608     goto done;
1609 
1610   (void) mutexObj_unlock (env, mutexObj, &mcache);
1611 
1612   SHOW_OLD_TROUBLE ();
1613 
1614 done:
1615   clean_mutexObj_cache (env, &mcache);
1616   if (TRACE_API_CALLS)
1617     tracing (" ==> VOID\n");
1618 }
1619 
1620 
1621 
1622 /* Free a mutex (isn't C fun?).  OK this time for it to be NULL.
1623    No failure conditions, for a change.  */
1624 static void
mutex_free_jni_impl(GMutex * mutex)1625 mutex_free_jni_impl (GMutex * mutex)
1626 {
1627   jobject mutexObj = (jobject) mutex;
1628   JNIEnv *env;
1629   union env_union e;
1630 
1631   e.jni_env = &env;
1632   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
1633 
1634   if (TRACE_API_CALLS)
1635     tracing ("mutex_free_jni_impl(%p)", mutexObj);
1636 
1637   freeObject (env, mutexObj);
1638 
1639   if (TRACE_API_CALLS)
1640     tracing (" ==> VOID\n");
1641 }
1642 
1643 
1644 
1645 
1646 /************************************************************************/
1647 /* Condition variable code		     				*/
1648 /************************************************************************/
1649 
1650 /* Create a new condition variable.  This is a java.lang.Object for us. */
1651 static GCond *
cond_new_jni_impl(void)1652 cond_new_jni_impl (void)
1653 {
1654   jobject condObj;
1655   JNIEnv *env;
1656   union env_union e;
1657 
1658   if (TRACE_API_CALLS)
1659     tracing ("mutex_free_jni_impl()");
1660 
1661   e.jni_env = &env;
1662   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
1663 
1664   condObj = allocatePlainObject (env);
1665 
1666   if (TRACE_API_CALLS)
1667     tracing (" ==> %p\n", condObj);
1668 
1669   return (GCond *) condObj;
1670 }
1671 
1672 /*  Signal on a condition variable.  This is simply calling Object.notify
1673  * for us.
1674  */
1675 static void
cond_signal_jni_impl(GCond * gcond)1676 cond_signal_jni_impl (GCond * gcond)
1677 {
1678   JNIEnv *env;
1679   union env_union e;
1680   jobject condObj = (jobject) gcond;
1681 
1682   if (TRACE_API_CALLS)
1683     tracing ("cond_signal_jni_impl(condObj = %p)", condObj);
1684 
1685   e.jni_env = &env;
1686   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
1687   if (setup_cache (env) < 0)
1688     goto done;
1689   HIDE_OLD_TROUBLE (env);
1690 
1691   assert (condObj);
1692 
1693   /* Must have locked an object to call notify */
1694   if (ENTER_MONITOR (env, condObj))
1695     goto done;
1696 
1697   (*env)->CallVoidMethod (env, condObj, obj_notify_mth);
1698   if (MAYBE_BROKEN (env, "cannot signal mutex with Object.notify()"))
1699     {
1700       if (EXIT_MONITOR (env, condObj))
1701 	BADLY_BROKEN1 ("Failed to unlock a monitor; the VM may deadlock.");
1702       goto done;
1703     }
1704 
1705   EXIT_MONITOR (env, condObj);
1706 
1707   SHOW_OLD_TROUBLE ();
1708 
1709 done:
1710   if (TRACE_API_CALLS)
1711     tracing (" ==> VOID\n");
1712 }
1713 
1714 /*  Broadcast to all waiting on a condition variable.  This is simply
1715  * calling Object.notifyAll for us.
1716  */
1717 static void
cond_broadcast_jni_impl(GCond * gcond)1718 cond_broadcast_jni_impl (GCond * gcond)
1719 {
1720   jobject condObj = (jobject) gcond;
1721   JNIEnv *env;
1722   union env_union e;
1723 
1724   if (TRACE_API_CALLS)
1725     tracing ("cond_broadcast_jni_impl(condObj=%p)", condObj);
1726 
1727   e.jni_env = &env;
1728   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
1729   if (setup_cache (env) < 0)
1730     goto done;
1731   HIDE_OLD_TROUBLE (env);
1732 
1733   assert (condObj);
1734   /* Must have locked an object to call notifyAll */
1735   if (ENTER_MONITOR (env, condObj))
1736     goto done;
1737 
1738   (*env)->CallVoidMethod (env, condObj, obj_notifyall_mth);
1739   if (MAYBE_BROKEN (env, "cannot broadcast to mutex with Object.notify()"))
1740     {
1741       EXIT_MONITOR (env, condObj);
1742       goto done;
1743     }
1744 
1745   EXIT_MONITOR (env, condObj);
1746 
1747   SHOW_OLD_TROUBLE ();
1748 
1749 done:
1750   if (TRACE_API_CALLS)
1751     tracing (" ==> VOID\n");
1752 }
1753 
1754 
1755 /* Wait on a condition variable.  For us, this simply means calling
1756  * Object.wait.
1757  *
1758  * Throws a Java exception on trouble; may leave the mutexes set arbitrarily.
1759  * XXX TODO: Further improve error recovery.
1760  */
1761 static void
cond_wait_jni_impl(GCond * gcond,GMutex * gmutex)1762 cond_wait_jni_impl (GCond * gcond, GMutex * gmutex)
1763 {
1764   struct mutexObj_cache cache;
1765   jobject condObj = (jobject) gcond;
1766   jobject mutexObj = (jobject) gmutex;
1767   JNIEnv *env;
1768   union env_union e;
1769 
1770   if (TRACE_API_CALLS)
1771     tracing ("cond_wait_jni_impl(condObj=%p, mutexObj=%p)",
1772 	     condObj, mutexObj);
1773 
1774   e.jni_env = &env;
1775   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
1776   if (setup_cache (env) < 0)
1777     goto done;
1778   HIDE_OLD_TROUBLE (env);
1779 
1780   assert (condObj);
1781   assert (mutexObj);
1782   /* Must have locked a Java object to call wait on it */
1783   if (ENTER_MONITOR (env, condObj) < 0)
1784     goto done;
1785 
1786   /* Our atomicity is now guaranteed; we're protected by the Java monitor on
1787      condObj.  Unlock the GMutex. */
1788   if (mutexObj_unlock (env, mutexObj, &cache))
1789     goto done;
1790 
1791   (*env)->CallVoidMethod (env, condObj, obj_wait_mth);
1792   if (MAYBE_BROKEN (env, "cannot wait on condObj"))
1793     {
1794       EXIT_MONITOR (env, condObj);	/* ignore err checking */
1795       goto done;
1796     }
1797 
1798   /* Re-acquire the lock on the GMutex.  Do this while we're protected by the
1799      Java monitor on condObj. */
1800   if (mutexObj_lock (env, mutexObj, &cache))
1801     goto done;
1802 
1803   EXIT_MONITOR (env, condObj);
1804 
1805   SHOW_OLD_TROUBLE ();
1806 
1807 done:
1808   if (TRACE_API_CALLS)
1809     tracing (" ==> VOID\n");
1810 }
1811 
1812 
1813 /** Wait on a condition variable until a timeout.  This is a little tricky
1814  * for us.  We first call Object.wait(J) giving it the appropriate timeout
1815  * value.  On return, we check whether an InterruptedException happened.  If
1816  * so, that is Java-speak for wait timing out.
1817  *
1818  * We return FALSE if we timed out.  Return TRUE if the condition was
1819  * signalled first, before we timed out.
1820  *
1821  * In case of trouble we throw a Java exception.  Whether we return FALSE or
1822  * TRUE depends upon whether the condition was raised before the trouble
1823  * happened.
1824  *
1825  * I believe that this function goes to the proper lengths to try to unlock
1826  * all of the locked mutexes and monitors, as appropriate, and that it further
1827  * tries to make sure that the thrown exception is the current one, not any
1828  * future cascaded one from something like a failure to unlock the monitors.
1829  */
1830 static gboolean
cond_timed_wait_jni_impl(GCond * gcond,GMutex * gmutex,GTimeVal * end_time)1831 cond_timed_wait_jni_impl (GCond * gcond, GMutex * gmutex, GTimeVal * end_time)
1832 {
1833   JNIEnv *env;
1834   union env_union e;
1835   jlong time_millisec;
1836   jint time_nanosec;
1837   jthrowable cause;
1838   jobject condObj = (jobject) gcond;
1839   jobject mutexObj = (jobject) gmutex;
1840   gboolean condRaised = FALSE;	/*  Condition has not been raised yet. */
1841   struct mutexObj_cache cache;
1842   gboolean interrupted;
1843 
1844   if (TRACE_API_CALLS)
1845     {
1846       tracing ("cond_timed_wait_jni_impl(cond=%p, mutex=%p,"
1847 	       " end_time=< sec=%lu, usec=%lu >)", condObj, mutexObj,
1848 	       (unsigned long) end_time->tv_sec,
1849 	       (unsigned long) end_time->tv_usec);
1850     }
1851 
1852 
1853   e.jni_env = &env;
1854   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
1855   if (setup_cache (env) < 0)
1856     goto done;
1857   HIDE_OLD_TROUBLE (env);
1858 
1859   time_millisec = end_time->tv_sec * 1000 + end_time->tv_usec / 1000;
1860   time_nanosec = 1000 * (end_time->tv_usec % 1000);
1861 
1862   /* Must have locked an object to call wait */
1863   if (ENTER_MONITOR (env, condObj) < 0)
1864     goto done;
1865 
1866   if (mutexObj_unlock (env, mutexObj, &cache) < 0)
1867     {
1868       if (EXIT_MONITOR (env, condObj) < 0)
1869 	criticalMsg
1870 	  ("Unable to unlock an existing lock on a condition; your proram may deadlock");
1871       goto done;
1872     }
1873 
1874 
1875   (*env)->CallVoidMethod (env, condObj, obj_wait_nanotime_mth,
1876 			  time_millisec, time_nanosec);
1877 
1878   /* If there was trouble, save that fact, and the reason for the trouble.  We
1879      want to respond to this condition as fast as possible. */
1880   cause = (*env)->ExceptionOccurred (env);
1881 
1882   if ( ! cause )
1883     {
1884       condRaised = TRUE;	/* condition was signalled */
1885     }
1886   else if ((*env)->IsInstanceOf (env, cause, interrupted_exception_class))
1887     {
1888       condRaised = FALSE;	/* Condition was not raised before timeout.
1889 				   (This is redundant with the initialization
1890 				   of condRaised above) */
1891       (*env)->ExceptionClear (env);	/* Clear the InterruptedException. */
1892       cause = NULL;		/* no pending cause now.  */
1893     }
1894   else
1895     {
1896       interrupted = FALSE;	/* Trouble, but not because of
1897 				   InterruptedException.  Assume the condition
1898 				   was not raised. */
1899       /* Leave condRaised set to FALSE */
1900     }
1901 
1902   /* Irrespective of whether there is a pending problem to report, go ahead
1903      and try to clean up.  This may end up throwing an exception that is
1904      different from the one that was thrown by the call to Object.wait().
1905      So we will override it with the first exception (don't want to have
1906      cascading problems). */
1907   if (mutexObj_lock (env, mutexObj, &cache) && !cause)
1908     {
1909       cause = (*env)->ExceptionOccurred (env);
1910       assert (cause);
1911     }
1912 
1913   if (EXIT_MONITOR (env, condObj) && !cause)
1914     {
1915       cause = (*env)->ExceptionOccurred (env);
1916       assert (cause);
1917     }
1918 
1919   if (cause)			/* Raise the first cause. */
1920     {
1921       BROKEN_CAUSE (env, cause, "error in timed wait or during its cleanup");
1922       goto done;
1923     }
1924 
1925   SHOW_OLD_TROUBLE ();
1926 
1927 done:
1928   if (TRACE_API_CALLS)
1929     tracing (" ==> condRaised = %s\n", condRaised ? "TRUE" : "FALSE");
1930   return condRaised;
1931 }
1932 
1933 
1934 /* Free a condition variable.  (isn't C fun?).  Can not fail. */
1935 static void
cond_free_jni_impl(GCond * cond)1936 cond_free_jni_impl (GCond * cond)
1937 {
1938   jobject condObj = (jobject) cond;
1939   JNIEnv *env;
1940   union env_union e;
1941 
1942   if (TRACE_API_CALLS)
1943     tracing ("cond_free_jni_impl(condObj = %p)", condObj);
1944   e.jni_env = &env;
1945   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
1946 
1947   freeObject (env, condObj);
1948 
1949   if (TRACE_API_CALLS)
1950     tracing (" ==> VOID\n");
1951 }
1952 
1953 
1954 /************************************************************************/
1955 /* Thread-local data code		     				*/
1956 /************************************************************************/
1957 
1958 /* Create a new thread-local key.  We use java.lang.ThreadLocal objects
1959  * for this.  This returns the pointer representation of a Java global
1960  * reference.
1961  *
1962  * We will throw a Java exception and return NULL in case of failure.
1963  */
1964 static GPrivate *
private_new_jni_impl(GDestroyNotify notify)1965 private_new_jni_impl (GDestroyNotify notify __attribute__ ((unused)))
1966 {
1967   JNIEnv *env;
1968   union env_union e;
1969   jobject lcl_key;
1970   jobject global_key;
1971   GPrivate *gkey = NULL;	/* Error return code */
1972 
1973   if (TRACE_API_CALLS)
1974     tracing ("private_new_jni_impl()");
1975 
1976   e.jni_env = &env;
1977   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
1978   if (setup_cache (env) < 0)
1979     goto done;
1980   HIDE_OLD_TROUBLE (env);
1981 
1982   lcl_key = (*env)->NewObject (env, threadlocal_class, threadlocal_ctor);
1983   if ( ! lcl_key )
1984     {
1985       BROKEN (env, "cannot allocate a ThreadLocal");
1986       goto done;
1987     }
1988 
1989   global_key = ((*env)->NewGlobalRef (env, lcl_key));
1990   DELETE_LOCAL_REF (env, lcl_key);
1991   if ( ! global_key)
1992     {
1993       NEW_BROKEN (env, "cannot create a GlobalRef to a new ThreadLocal");
1994       goto done;
1995     }
1996 
1997   gkey = (GPrivate *) global_key;
1998   SHOW_OLD_TROUBLE ();
1999 
2000 done:
2001   if (TRACE_API_CALLS)
2002     tracing (" ==> %p\n", (void *) gkey);
2003 
2004   return gkey;
2005 }
2006 
2007 /*  Get this thread's value for a thread-local key.  This is simply
2008  * ThreadLocal.get for us.  Return NULL if no value.  (I can't think of
2009  * anything else to do.)
2010  */
2011 static gpointer
private_get_jni_impl(GPrivate * gkey)2012 private_get_jni_impl (GPrivate * gkey)
2013 {
2014   JNIEnv *env;
2015   union env_union e;
2016   jobject val_wrapper;
2017   jobject keyObj = (jobject) gkey;
2018   gpointer thread_specific_data = NULL;	/* Init to the error-return value */
2019 
2020   jlong val;
2021 
2022   if (TRACE_API_CALLS)
2023     tracing ("private_get_jni_impl(keyObj=%p)", keyObj);
2024 
2025   e.jni_env = &env;
2026   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
2027   if (setup_cache (env) < 0)
2028     goto done;
2029   HIDE_OLD_TROUBLE (env);
2030 
2031   val_wrapper = (*env)->CallObjectMethod (env, keyObj, threadlocal_get_mth);
2032   if (MAYBE_BROKEN (env, "cannot find thread-local object"))
2033     goto done;
2034 
2035   if (! val_wrapper )
2036     {
2037       /* It's Java's "null" object.  No ref found.  This is OK; we must never
2038          have set a value in this thread.  Note that this next statement is
2039          not necessary, strictly speaking, since we're already initialized to
2040          NULL.  A good optimizing C compiler will detect that and optimize out
2041          this statement. */
2042       thread_specific_data = NULL;
2043       goto done;
2044     }
2045 
2046   val = (*env)->CallLongMethod (env, val_wrapper, long_longValue_mth);
2047 
2048   if (MAYBE_BROKEN (env, "cannot get thread local value"))
2049     goto done;
2050 
2051   thread_specific_data = (gpointer) (intptr_t) val;
2052 
2053   /* Only re-raise the old pending exception if a new one hasn't come along to
2054      supersede it.  */
2055   SHOW_OLD_TROUBLE ();
2056 
2057 done:
2058 
2059   if (TRACE_API_CALLS)
2060     tracing (" ==> %p\n", thread_specific_data);
2061 
2062   return thread_specific_data;
2063 }
2064 
2065 /* Set this thread's value for a thread-local key.  This is simply
2066  * ThreadLocal.set() for us.
2067  */
2068 static void
private_set_jni_impl(GPrivate * gkey,gpointer thread_specific_data)2069 private_set_jni_impl (GPrivate * gkey, gpointer thread_specific_data)
2070 {
2071   JNIEnv *env;
2072   union env_union e;
2073   jobject val_wrapper;
2074   jobject keyObj = (jobject) gkey;
2075 
2076 
2077   if (TRACE_API_CALLS)
2078     tracing ("private_set_jni_impl(keyObj=%p, thread_specific_data=%p)",
2079 	     keyObj, thread_specific_data);
2080 
2081   e.jni_env = &env;
2082   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
2083   if (setup_cache (env) < 0)
2084     goto done;
2085   HIDE_OLD_TROUBLE (env);
2086 
2087   /* We are just going to always use a Java long to represent a C pointer.
2088      Otherwise all of the code would end up being conditionalized for various
2089      pointer sizes, and that seems like too much of a hassle, in order to save
2090      a paltry few bytes, especially given the horrendous overhead of JNI in
2091      any case.
2092    */
2093 
2094   val_wrapper = (*env)->NewObject (env, long_class, long_ctor,
2095 				   (jlong) (intptr_t) thread_specific_data);
2096   if ( ! val_wrapper )
2097     {
2098       BROKEN (env, "cannot create a java.lang.Long");
2099       goto done;
2100     }
2101 
2102   /* At this point, we now have set lcl_obj as a numeric class that wraps
2103      around the thread-specific data we were given. */
2104   (*env)->CallVoidMethod (env, keyObj, threadlocal_set_mth, val_wrapper);
2105   if (MAYBE_BROKEN (env, "cannot set thread local value"))
2106     goto done;
2107 
2108   SHOW_OLD_TROUBLE ();
2109 done:
2110   if (TRACE_API_CALLS)
2111     tracing (" ==> VOID\n");
2112 }
2113 
2114 
2115 /** Create an object of type gnu.java.awt.peer.gtk.GThreadNativeMethodRunner.
2116     Run it.
2117 
2118     We need to create joinable threads.  We handle the notion of a joinable
2119     thread by determining whether or not we are going to maintain a permanent
2120     hard reference to it until it croaks.
2121 
2122     Posix does not appear to have a Java-like concept of daemon threads, where
2123     the JVM will exit when there are only daemon threads running.
2124 
2125     Error handling:
2126 
2127     To quote from the glib guide:
2128        "GError should only be used to report recoverable runtime errors, never
2129         to report programming errors."
2130 
2131     So how do we consider the failure to create a thread?  Well, each of the
2132     failure cases in this function are discussed, and none of them are really
2133     recoverable.
2134 
2135     The glib library is really designed so that you should fail
2136     catastrophically in case of "programming errors".  The only error defined
2137     for the GThread functions is G_THREAD_ERROR_AGAIN, and that for
2138     thread_create.
2139 
2140     Most of these GThread functions could fail if we run out of memory, for
2141     example, but the only one capable of reporting that fact is
2142     thread_create. */
2143 static void
thread_create_jni_impl(GThreadFunc func,gpointer data,gulong stack_size,gboolean joinable,gboolean bound,GThreadPriority gpriority,gpointer threadIDp,GError ** errorp)2144 thread_create_jni_impl (GThreadFunc	    func,
2145 			gpointer            data,
2146 			gulong              stack_size __attribute__((unused)),
2147 			gboolean            joinable,
2148 			gboolean            bound __attribute__((unused)),
2149 			GThreadPriority     gpriority,
2150 			/* This prototype is horrible.  threadIDp is actually
2151 			   a gpointer to the thread's thread-ID.  Which is,
2152 			   of course, itself a gpointer-typed value.  Ouch. */
2153 			gpointer            threadIDp,
2154 			/* Do not touch the GError stuff unless you have
2155 			   RECOVERABLE trouble.   There is no recoverable
2156 			   trouble in this implementation.  */
2157 			GError	      **errorp __attribute__((unused)))
2158 {
2159   JNIEnv *env;
2160   union env_union e;
2161   union func_union f;
2162   jboolean jjoinable = joinable;
2163   jobject newThreadObj;
2164   gpointer threadID;		/* to be filled in */
2165 
2166   if (TRACE_API_CALLS)
2167     {
2168       f.g_func = func;
2169       tracing ("thread_create_jni_impl(func=%p, data=%p, joinable=%s,"
2170                " threadIDp=%p, *(int *) threadIDp = %d)",
2171                f.void_func, data, joinable ? "TRUE" : "FALSE",
2172                threadIDp, *(int *) threadIDp);
2173     }
2174 
2175   e.jni_env = &env;
2176   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
2177   if (setup_cache (env) < 0)
2178     {
2179       /*  The failed call to setup the cache is certainly not recoverable;
2180 	  not appropriate for G_THREAD_ERROR_AGAIN.  */
2181       *(gpointer *) threadIDp = NULL;
2182       goto done;
2183     }
2184   HIDE_OLD_TROUBLE (env);
2185 
2186   /* If a thread is joinable, then notify its constructor.  The constructor
2187      will enter a hard reference for it, and the hard ref. won't go away until
2188      the thread has been joined. */
2189   newThreadObj =
2190     (*env)->NewObject (env, runner_class, runner_ctor,
2191                        (jlong) (intptr_t) func, (jlong) (intptr_t) data,
2192                        jjoinable);
2193   if ( ! newThreadObj )
2194     {
2195       BROKEN (env, "creating a new thread failed in the constructor");
2196       *(gpointer *) threadIDp = NULL;
2197       /*  The failed call to the constructor does not throw any errors such
2198 	  that G_THREAD_ERROR_AGAIN is appropriate.  No other recoverable
2199 	  errors defined.  Once again, we go back to the VM. */
2200       goto done;
2201     }
2202 
2203   if (threadObj_set_priority (env, newThreadObj, gpriority) < 0)
2204     {
2205       *(gpointer *) threadIDp = NULL;
2206       /* None of these possible exceptions from Thread.setPriority() are
2207 	 recoverable, so they are not appropriate for EAGAIN.  So we should
2208 	 fail. */
2209       goto done;
2210     }
2211 
2212   (*env)->CallVoidMethod (env, runner_class, runner_start_mth);
2213 
2214   if (MAYBE_BROKEN (env, "starting a new thread failed"))
2215     {
2216       *(gpointer *) threadIDp = NULL;
2217       /* The only exception Thread.start() throws is
2218 	 IllegalStateException.  And that would indicate a programming error.
2219 
2220 	 So there are no situations such that G_THREAD_ERROR_AGAIN would be
2221 	 OK.
2222 
2223 	 So, we don't use g_set_error() here to perform any error reporting.
2224 	 */
2225       goto done;
2226     }
2227 
2228   threadID = getThreadIDFromThread (env, newThreadObj);
2229 
2230   *(gpointer *) threadIDp = threadID;
2231   SHOW_OLD_TROUBLE ();
2232 
2233 done:
2234   if (TRACE_API_CALLS)
2235     tracing (" ==> (threadID = %p) \n", threadID);
2236 }
2237 
2238 
2239 /* Wraps a call to g_thread_yield. */
2240 static void
thread_yield_jni_impl(void)2241 thread_yield_jni_impl (void)
2242 {
2243   JNIEnv *env;
2244   union env_union e;
2245 
2246   if (TRACE_API_CALLS)
2247     tracing ("thread_yield_jni_impl()");
2248 
2249   e.jni_env = &env;
2250   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
2251   if (setup_cache (env) < 0)
2252     goto done;
2253   HIDE_OLD_TROUBLE (env);
2254 
2255   (*env)->CallStaticVoidMethod (env, thread_class, thread_yield_mth);
2256   if (MAYBE_BROKEN (env, "Thread.yield() failed"))
2257     goto done;
2258 
2259   SHOW_OLD_TROUBLE ();
2260 
2261 done:
2262   if (TRACE_API_CALLS)
2263     tracing (" ==> VOID\n");
2264 }
2265 
2266 
2267 static void
thread_join_jni_impl(gpointer threadID)2268 thread_join_jni_impl (gpointer threadID)
2269 {
2270   JNIEnv *env;
2271   union env_union e;
2272   jobject threadObj = NULL;
2273 
2274   if ( TRACE_API_CALLS )
2275     tracing ("thread_join_jni_impl(threadID=%p) ", threadID);
2276 
2277   e.jni_env = &env;
2278   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
2279   if (setup_cache (env) < 0)
2280     goto done;
2281   HIDE_OLD_TROUBLE (env);
2282 
2283   threadObj = getThreadFromThreadID (env, threadID);
2284   if ( ! threadObj )		/* Already reported with BROKEN  */
2285     goto done;
2286 
2287   (*env)->CallVoidMethod (env, threadObj, thread_join_mth);
2288   if (MAYBE_BROKEN (env, "Thread.join() failed"))
2289     goto done;
2290 
2291 
2292   (*env)->CallStaticVoidMethod
2293     (env, runner_class, runner_deRegisterJoinable_mth, threadObj);
2294   if (MAYBE_BROKEN (env, "Thread.deRegisterJoinableThread() failed"))
2295     goto done;
2296 
2297   SHOW_OLD_TROUBLE ();
2298 
2299 done:
2300   DELETE_LOCAL_REF (env, threadObj);
2301   if (TRACE_API_CALLS)
2302     tracing (" ==> VOID \n");
2303 }
2304 
2305 /* Terminate the current thread.  Unlike pthread_exit(), here we do not need
2306    to bother with a return value or exit value for the thread which is about
2307    to croak.  (The gthreads abstraction doesn't use it.)  However, we *do*
2308    need to bail immediately.  We handle this with Thread.stop(), which is
2309    a deprecated method.
2310 
2311    It's deprecated since we might leave objects protected by monitors in
2312    half-constructed states on the way out -- Thread.stop() throws a
2313    ThreadDeath exception, which is usually unchecked.  There is no good
2314    solution that I can see. */
2315 static void
thread_exit_jni_impl(void)2316 thread_exit_jni_impl (void)
2317 {
2318   JNIEnv *env;
2319   union env_union e;
2320   jobject this_thread;
2321 
2322   if (TRACE_API_CALLS)
2323     tracing ("thread_exit_jni_impl() ");
2324 
2325   e.jni_env = &env;
2326   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
2327   if (setup_cache (env) < 0)
2328     goto done;
2329 
2330   HIDE_OLD_TROUBLE (env);
2331 
2332   this_thread = (*env)->
2333     CallStaticObjectMethod (env, thread_class, thread_current_mth);
2334 
2335   if ( ! this_thread )
2336     {
2337       BROKEN (env, "cannot get current thread");
2338       goto done;
2339     }
2340 
2341   (*env)->CallVoidMethod (env, this_thread, thread_stop_mth);
2342   if (MAYBE_BROKEN (env, "cannot call Thread.stop() on current thread"))
2343     goto done;
2344 
2345   SHOW_OLD_TROUBLE ();
2346 
2347 done:
2348   if (TRACE_API_CALLS)
2349     tracing (" ==> VOID \n");
2350 }
2351 
2352 
2353 /* Translate a GThreadPriority to a Java priority level. */
2354 static jint
javaPriorityLevel(GThreadPriority priority)2355 javaPriorityLevel (GThreadPriority priority)
2356 {
2357   /* We have these fields in java.lang.Thread to play with:
2358 
2359      static int MIN_PRIORITY     The minimum priority that a thread can have.
2360      static int NORM_PRIORITY    The default priority that is assigned to a
2361      thread.
2362      static int MAX_PRIORITY     The maximum priority that a thread can have.
2363 
2364      We get these from the header file generated by javah, even though they're
2365      documented as being 1, 5, and 10.
2366    */
2367   static const jint minJPri	=
2368     gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MIN_PRIORITY;
2369   static const jint normJPri	=
2370     gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY;
2371   static const jint maxJPri	=
2372     gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY;
2373 
2374   switch (priority)
2375     {
2376     case G_THREAD_PRIORITY_LOW:
2377       return minJPri;
2378       break;
2379 
2380     default:
2381       assert_not_reached ();
2382       /* Deliberate fall-through if assertions are turned off; also shuts up
2383          GCC warnings if they're turned on.   */
2384     case G_THREAD_PRIORITY_NORMAL:
2385       return normJPri;
2386       break;
2387 
2388     case G_THREAD_PRIORITY_HIGH:
2389       return (normJPri + maxJPri) / 2;
2390       break;
2391 
2392     case G_THREAD_PRIORITY_URGENT:
2393       return maxJPri;
2394       break;
2395     }
2396 }
2397 
2398 
2399 /** It would be safe not to implement this, according to the JNI docs, since
2400     not all platforms do thread priorities.  However, we might as well
2401     provide the hint for those who want it.
2402 */
2403 static void
thread_set_priority_jni_impl(gpointer gThreadID,GThreadPriority gpriority)2404 thread_set_priority_jni_impl (gpointer gThreadID, GThreadPriority gpriority)
2405 {
2406   jobject threadObj = NULL;
2407   JNIEnv *env;
2408   union env_union e;
2409 
2410   if (TRACE_API_CALLS)
2411     tracing ("thread_set_priority_jni_impl(gThreadID=%p, gpriority = %u) ",
2412 	     gThreadID, gpriority);
2413 
2414   e.jni_env = &env;
2415   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
2416 
2417   if (setup_cache (env) < 0)
2418     goto done;
2419 
2420   HIDE_OLD_TROUBLE (env);
2421 
2422 
2423   threadObj = getThreadFromThreadID (env, gThreadID);
2424   if ( ! threadObj)		/* Reported with BROKEN already.  */
2425     goto done;
2426 
2427   if (threadObj_set_priority (env, threadObj, gpriority))
2428     goto done;
2429 
2430   SHOW_OLD_TROUBLE ();
2431 
2432 done:
2433   DELETE_LOCAL_REF (env, threadObj);
2434 
2435   if (TRACE_API_CALLS)
2436     tracing (" ==> VOID\n");
2437 }
2438 
2439 
2440 /** It would be safe not to implement this, according to the JNI docs, since
2441     not all platforms do thread priorities.  However, we might as well
2442     provide the hint for those who want it.
2443 
2444     -1 on failure, 0 on success. */
2445 static int
threadObj_set_priority(JNIEnv * env,jobject threadObj,GThreadPriority gpriority)2446 threadObj_set_priority (JNIEnv * env, jobject threadObj,
2447 			GThreadPriority gpriority)
2448 {
2449   jint javaPriority = javaPriorityLevel (gpriority);
2450   (*env)->CallVoidMethod (env, threadObj, thread_setPriority_mth,
2451 			  javaPriority);
2452   return MAYBE_BROKEN (env, "Thread.setPriority() failed");
2453 }
2454 
2455 
2456 /** Return the result of Thread.currentThread(), a static method. */
2457 static void
thread_self_jni_impl(gpointer my_thread_IDp)2458 thread_self_jni_impl (/* Another confusing glib prototype.  This is
2459 			 actually  a gpointer to the thread's thread-ID.
2460 			 Which is, of course, a gpointer. */
2461 		      gpointer my_thread_IDp)
2462 {
2463   JNIEnv *env;
2464   union env_union e;
2465   jobject this_thread;
2466   gpointer my_threadID;
2467 
2468   if (TRACE_API_CALLS)
2469     tracing ("thread_self_jni_impl(my_thread_IDp=%p)", my_thread_IDp);
2470 
2471   e.jni_env = &env;
2472   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
2473 
2474   if (setup_cache (env) < 0)
2475     return;
2476 
2477   HIDE_OLD_TROUBLE (env);
2478 
2479   this_thread = (*env)->
2480     CallStaticObjectMethod (env, thread_class, thread_current_mth);
2481   if (! this_thread )
2482     {
2483       BROKEN (env, "cannot get current thread");
2484       my_threadID = NULL;
2485       goto done;
2486     }
2487 
2488   my_threadID = getThreadIDFromThread (env, this_thread);
2489   SHOW_OLD_TROUBLE ();
2490 
2491 done:
2492   if (TRACE_API_CALLS)
2493     tracing (" ==> (my_threadID = %p) \n", my_threadID);
2494 
2495   *(gpointer *) my_thread_IDp = my_threadID;
2496 }
2497 
2498 
2499 static gboolean
thread_equal_jni_impl(gpointer thread1,gpointer thread2)2500 thread_equal_jni_impl (gpointer thread1, gpointer thread2)
2501 {
2502   JNIEnv *env;
2503   union env_union e;
2504 
2505   gpointer threadID1 = *(gpointer *) thread1;
2506   gpointer threadID2 = *(gpointer *) thread2;
2507 
2508   jobject thread1_obj = NULL;
2509   jobject thread2_obj = NULL;
2510   gboolean ret;
2511 
2512   if (TRACE_API_CALLS)
2513     tracing ("thread_equal_jni_impl(threadID1=%p, threadID2=%p)",
2514 	     threadID1, threadID2);
2515 
2516   e.jni_env = &env;
2517   (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1);
2518   if (setup_cache (env) < 0)
2519     {
2520       ret = FALSE;		/* what is safer?  We really don't ever want
2521 				   to return from here.  */
2522       goto done;
2523     }
2524 
2525   HIDE_OLD_TROUBLE (env);
2526   thread1_obj = getThreadFromThreadID (env, threadID1);
2527   thread2_obj = getThreadFromThreadID (env, threadID2);
2528 
2529   ret = (*env)->CallBooleanMethod (env, thread1_obj,
2530 				   thread_equals_mth, thread2_obj);
2531 
2532   if (MAYBE_BROKEN (env, "Thread.equals() failed"))
2533     {
2534       ret = FALSE;
2535       goto done;
2536     }
2537 
2538   SHOW_OLD_TROUBLE ();
2539 
2540 
2541 done:
2542   DELETE_LOCAL_REF (env, thread1_obj);
2543   DELETE_LOCAL_REF (env, thread2_obj);
2544 
2545   if (TRACE_API_CALLS)
2546     tracing (" ==> %s\n", ret ? "TRUE" : "FALSE");
2547 
2548   return ret;
2549 }
2550 
2551 
2552 
2553 
2554 /************************************************************************/
2555 /* GLIB interface			     				*/
2556 /************************************************************************/
2557 
2558 /* set of function pointers to give to glib. */
2559 GThreadFunctions cp_gtk_portable_native_sync_jni_functions = {
2560   mutex_new_jni_impl,		/* mutex_new */
2561   mutex_lock_jni_impl,		/* mutex_lock */
2562   mutex_trylock_jni_impl,	/* mutex_trylock */
2563   mutex_unlock_jni_impl,	/* mutex_unlock */
2564   mutex_free_jni_impl,		/* mutex_free */
2565   cond_new_jni_impl,		/* cond_new */
2566   cond_signal_jni_impl,		/* cond_signal */
2567   cond_broadcast_jni_impl,	/* cond_broadcast */
2568   cond_wait_jni_impl,		/* cond_wait */
2569   cond_timed_wait_jni_impl,	/* cond_timed_wait */
2570   cond_free_jni_impl,		/* cond_free */
2571   private_new_jni_impl,		/* private_new */
2572   private_get_jni_impl,		/* private_get */
2573   private_set_jni_impl,		/* private_set */
2574   thread_create_jni_impl,	/* thread_create */
2575   thread_yield_jni_impl,	/* thread_yield */
2576   thread_join_jni_impl,		/* thread_join */
2577   thread_exit_jni_impl,		/* thread_exit */
2578   thread_set_priority_jni_impl,	/* thread_set_priority */
2579   thread_self_jni_impl,		/* thread_self */
2580   thread_equal_jni_impl,	/* thread_equal */
2581 };
2582 
2583 
2584 /* Keep c-font-lock-extra-types in alphabetical order. */
2585 /* Local Variables: */
2586 /* c-file-style: "gnu" */
2587 /* c-font-lock-extra-types: ("\\sw+_t" "gboolean" "GError" "gpointer"
2588    "GPrivate" "GThreadFunc" "GThreadFunctions" "GThreadPriority"
2589    "gulong"
2590    "JNIEnv"
2591    "jboolean" "jclass" "jfieldID" "jint" "jlong" "jmethodID" "jobject" "jstring" "jthrowable" ) */
2592 /* End: */
2593