OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.git] / libjava / classpath / native / jni / gtk-peer / gthread-jni.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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 *
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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 \f
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: */