Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / jni / gtk-peer / gthread-jni.c
blobd66c5a08087b53380681cdbb455f518f66ae804c
1 /* gthread-jni.c -- JNI threading routines for GLIB
2 Copyright (C) 1998, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
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.
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. */
38 /************************************************************************/
39 /* Header */
40 /************************************************************************/
43 * @author Julian Dolby (dolby@us.ibm.com)
44 * @date February 7, 2003 implemented for GLIB v.1
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.
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.
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.
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.
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.
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).
77 * ACKNOWLEDGEMENT:
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
84 * NOTES:
86 * This code has been tested with Jikes RVM and with Kaffe.
88 * This code should have proper automated unit tests. I manually tested it
89 * by running an application that uses AWT. --Steven Augart
91 * MINOR NIT:
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.
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 )
114 #include <config.h>
116 /************************************************************************/
117 /* Configuration */
118 /************************************************************************/
120 /** Tracing and Reporting **/
121 #define TRACE_API_CALLS 0 /* announce entry and exit into each method,
122 by printing to stderr. */
124 #define TRACE_MONITORS 0 /* Every enterMonitor() and exitMonitor() goes
125 to stderr. */
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.
135 Use criticalMsg() to describe the problem.
138 #define EXPLAIN_BROKEN 1 /* Describe trouble that is serious enough to
139 be BROKEN. (Right now all trouble is at
140 least BROKEN.) */
142 /* There is no EXPLAIN_BADLY_BROKEN definition. We always explain
143 BADLY_BROKEN trouble, since there is no other way to report it. */
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.
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. */
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.
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
179 /** Performance tuning parameters **/
181 #define ENABLE_EXPENSIVE_ASSERTIONS 0 /* Enable expensive assertions? */
183 #define DELETE_LOCAL_REFS 1 /* Whether to delete local references.
185 JNI only guarantees that there wil be 16
186 available. (Jikes RVM provides an number
187 only limited by VM memory.)
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.
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.
200 We set this to 1 for GNU Classpath, since
201 one of our principles is "always go for the
202 most robust implementation" */
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.
209 As it stands, the code in this file
210 already needs one JNI 1.2 function:
211 GetEnv, in the JNI Invocation API.
213 TODO This code hasn't been tested yet.
214 And really hasn't been implemented yet.
217 /************************************************************************/
218 /* Global data */
219 /************************************************************************/
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() */
231 /* For Java thread priority constants. */
232 #include <gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h>
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
246 /* The VM handle. This is set in
247 Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit */
248 JavaVM *the_vm;
250 /* Unions used for type punning. */
251 union env_union
253 void **void_env;
254 JNIEnv **jni_env;
257 union func_union
259 void *void_func;
260 GThreadFunc g_func;
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));
270 static void criticalMsg (const char fmt[], ...)
271 __attribute__ ((format (printf, 1, 2)));
273 static void tracing (const char fmt[], ...)
274 __attribute__ ((format (printf, 1, 2)));
276 static jint javaPriorityLevel (GThreadPriority priority)
277 __attribute__ ((const));
279 /************************************************************************/
280 /* Trouble-handling, including utilities to reflect exceptions */
281 /* back to the VM. Also some status reporting. */
282 /************************************************************************/
284 /* How are we going to handle problems?
286 There are several approaches:
288 1) Report them with the GError mechanism.
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.
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.
299 3) Abort execution. This is what the glib functions themselves do for
300 errors that they can't report via GError.
302 Enable DIE_IF_BROKEN and/or DIE_IF_BADLY_BROKEN to
303 make this the default for BROKEN and/or BADLY_BROKEN trouble.
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.
309 There are some complications.
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.
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.
321 #define WHERE __FILE__ ":" G_STRINGIFY(__LINE__) ": "
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.
327 static void
328 fatalMsg (const char fmt[], ...)
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 ();
339 static void
340 criticalMsg (const char fmt[], ...)
342 va_list ap;
343 va_start (ap, fmt);
344 vfprintf (stderr, fmt, ap);
345 va_end (ap);
346 putc ('\n', stderr);
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[], ...)
354 va_list ap;
355 va_start (ap, fmt);
356 vfprintf (stderr, fmt, ap);
357 va_end (ap);
360 #define assert_not_reached() \
361 do \
363 fputs(WHERE "You should never get here. Aborting execution.\n", \
364 stderr); \
365 abort(); \
367 while(0)
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
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"
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)
393 #define DELETE_LOCAL_REF(env, ref) \
394 do \
396 if ( DELETE_LOCAL_REFS ) \
398 (*env)->DeleteLocalRef (env, ref); \
399 (ref) = NULL; \
402 while(0)
404 /* Cached info for Exception-wrapping */
406 jclass runtimeException_class; /* java.lang.RuntimeException */
407 jmethodID runtimeException_ctor; /* constructor for it */
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)
417 jstring jmessage;
418 gboolean describedException = FALSE; /* Did we already describe the
419 exception to stderr or the
420 equivalent? */
421 jthrowable wrapper;
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;
428 if (EXPLAIN_TROUBLE || (isBroken && EXPLAIN_BROKEN))
430 criticalMsg ("%s:%d: AWT JNI failure%s: %s\n", file, line,
431 isBroken ? " (BROKEN)" : "", message);
432 if (cause)
434 jthrowable currentException = (*env)->ExceptionOccurred (env);
436 if (cause == currentException)
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;
444 if ((*env)->Throw (env, cause))
446 BADLY_BROKEN1
447 ("Relaunching an exception with Throw failed.");
448 return -1;
451 else
453 DELETE_LOCAL_REF (env, currentException);
454 criticalMsg (WHERE
455 "currentException != cause; something else happened"
456 " while handling an exception.");
459 } /* if (EXPLAIN_TROUBLE) */
461 if (isBroken && DIE_IF_BROKEN)
462 fatalMsg ("%s:%d: Aborting execution; BROKEN: %s\n", file, line, message);
464 if ((buf = malloc (len)))
466 memset (buf, 0, len);
467 g_snprintf (buf, len, fmt, message, file, line);
468 jmessage = (*env)->NewStringUTF (env, buf);
469 free (buf);
471 else
473 jmessage = NULL;
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);
482 if (!wrapper)
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.
489 if (EXPLAIN_TROUBLE)
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);
500 BADLY_BROKEN1 ("Failure of JNI NewObject()"
501 " to make a java.lang.RuntimeException");
502 return -1;
506 /* throw it */
507 if ((*env)->Throw (env, wrapper))
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;
516 DELETE_LOCAL_REF (env, wrapper);
517 return 1;
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)
530 assert (cause);
531 return throw (env, cause, message, isBroken, file, line);
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.
540 * Returns 0 if no problems found (so no exception thrown), 1 if we rethrew an
541 * exception. Returns -1 on failure.
543 static int
544 maybe_rethrow (JNIEnv * env, const char *message, gboolean isBroken,
545 const char *file, int line)
547 jthrowable cause = (*env)->ExceptionOccurred (env);
548 int ret = 0;
550 /* rethrow if an exception happened */
551 if (cause)
553 ret = rethrow (env, cause, message, isBroken, file, line);
554 DELETE_LOCAL_REF (env, cause);
557 return 0;
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.
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__)
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__)
574 /* Like MAYBE_TROUBLE(), TROUBLE() is never used. */
575 #define TROUBLE(_env, _message) \
576 rethrow(_env, (*env)->ExceptionOccurred (env), _message, FALSE, \
577 __FILE__, __LINE__)
579 #define BROKEN(_env, _message) \
580 rethrow (_env, (*env)->ExceptionOccurred (env), _message, TRUE, \
581 __FILE__, __LINE__)
583 /* Like MAYBE_TROUBLE(), NEW_TROUBLE() is never used. */
584 #define NEW_TROUBLE(_env, _message) \
585 throw (_env, NULL, _message, FALSE, __FILE__, __LINE__)
587 #define NEW_BROKEN(_env, _message) \
588 throw (_env, NULL, _message, TRUE, __FILE__, __LINE__)
590 /* Like MAYBE_TROUBLE(), RETHROW_CAUSE() is never used. */
591 #define RETHROW_CAUSE(_env, _cause, _message) \
592 rethrow (_env, _cause, _message, FALSE, __FILE__, __LINE__)
594 #define BROKEN_CAUSE(_env, _cause, _message) \
595 rethrow (_env, _cause, _message, TRUE, __FILE__, __LINE__)
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.
603 These are #if'd out for these reasons:
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.)
611 2) They chew up more time and resources.
613 3) There does not ever seem to be old trouble -- the assertion in
614 HIDE_OLD_TROUBLE never goes off.
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.
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) )
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);
635 #define SHOW_OLD_TROUBLE() do \
637 assert ( NULL == (*env)->ExceptionOccurred (env) ) \
638 if (savedTrouble) \
640 if ((*env)->Throw (env, savedTrouble)) \
641 BADLY_BROKEN ("ReThrowing the savedTrouble failed"); \
643 DELETE_LOCAL_REF (env, savedTrouble); \
644 } while(0)
646 #endif /* 0 */
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.
653 If any errors while setting up the error cache, the world is BADLY_BROKEN.
655 May be called more than once.
657 Returns -1 if the cache was not initialized properly, 1 if it was.
659 static int
660 setup_exception_cache (JNIEnv * env)
662 static int exception_cache_initialized = 0; /* -1 for trouble, 1 for proper
663 init. */
665 jclass lcl_class; /* a class used for local refs */
667 if (exception_cache_initialized)
668 return exception_cache_initialized;
669 lcl_class = (*env)->FindClass (env, "java/lang/RuntimeException");
670 if ( ! lcl_class )
672 BADLY_BROKEN1 ("Broken Class library or VM?"
673 " Couldn't find java/lang/RuntimeException");
674 return exception_cache_initialized = -1;
676 /* Pin it down. */
677 runtimeException_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
678 DELETE_LOCAL_REF (env, lcl_class);
679 if (!runtimeException_class)
681 BADLY_BROKEN1 ("Serious trouble: could not turn"
682 " java.lang.RuntimeException into a global reference");
683 return exception_cache_initialized = -1;
686 runtimeException_ctor =
687 (*env)->GetMethodID (env, runtimeException_class, "<init>",
688 "(Ljava/lang/String;Ljava/lang/Throwable;)V");
689 if ( ! runtimeException_ctor )
691 BADLY_BROKEN1 ("Serious trouble: classpath couldn't find a"
692 " two-arg constructor for java/lang/RuntimeException");
693 return exception_cache_initialized = -1;
696 return exception_cache_initialized = 1;
700 /**********************************************************/
701 /***** The main cache *************************************/
702 /**********************************************************/
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.
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.
715 The code in jnilink.c has a similar objective. TODO: Consider using that
716 code instead.
718 --Steven Augart
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) */
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;
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() */
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() */
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 */
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() */
766 /* java.lang.InterruptedException */
767 static jclass interrupted_exception_class;
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)
778 jclass lcl_class;
779 static int initialized = 0; /* 1 means initialized, 0 means uninitialized,
780 -1 means mis-initialized */
782 if (initialized)
783 return initialized;
785 /* make sure we can report on trouble */
786 if (setup_exception_cache (env) < 0)
787 return initialized = -1;
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));
796 /* java.lang.Object and its methods */
797 lcl_class = (*env)->FindClass (env, "java/lang/Object");
798 if (!lcl_class)
800 BROKEN (env, "cannot find java.lang.Object");
801 return initialized = -1;
804 /* Pin it down. */
805 obj_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
806 DELETE_LOCAL_REF (env, lcl_class);
807 if (!obj_class)
809 BROKEN (env, "Cannot get a global reference to java.lang.Object");
810 return initialized = -1;
813 obj_ctor = (*env)->GetMethodID (env, obj_class, "<init>", "()V");
814 if (!obj_ctor)
816 BROKEN (env, "cannot find constructor for java.lang.Object");
817 return initialized = -1;
820 obj_notify_mth = (*env)->GetMethodID (env, obj_class, "notify", "()V");
821 if ( ! obj_notify_mth )
823 BROKEN (env, "cannot find java.lang.Object.notify()V");
824 return initialized = -1;
827 obj_notifyall_mth =
828 (*env)->GetMethodID (env, obj_class, "notifyAll", "()V");
829 if ( ! obj_notifyall_mth)
831 BROKEN (env, "cannot find java.lang.Object.notifyall()V");
832 return initialized = -1;
835 obj_wait_mth = (*env)->GetMethodID (env, obj_class, "wait", "()V");
836 if ( ! obj_wait_mth )
838 BROKEN (env, "cannot find Object.<wait()V>");
839 return initialized = -1;
842 obj_wait_nanotime_mth =
843 (*env)->GetMethodID (env, obj_class, "wait", "(JI)V");
844 if ( ! obj_wait_nanotime_mth )
846 BROKEN (env, "cannot find Object.<wait(JI)V>");
847 return initialized = -1;
850 /* GThreadMutex and its methods */
851 lcl_class = (*env)->FindClass (env, "gnu/java/awt/peer/gtk/GThreadMutex");
852 if ( ! lcl_class)
854 BROKEN (env, "cannot find gnu.java.awt.peer.gtk.GThreadMutex");
855 return initialized = -1;
857 /* Pin it down. */
858 mutex_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
859 DELETE_LOCAL_REF (env, lcl_class);
860 if ( ! mutex_class)
862 BROKEN (env, "Cannot get a global reference to GThreadMutex");
863 return initialized = -1;
866 mutex_ctor = (*env)->GetMethodID (env, mutex_class, "<init>", "()V");
867 if ( ! mutex_ctor)
869 BROKEN (env, "cannot find zero-arg constructor for GThreadMutex");
870 return initialized = -1;
873 mutex_potentialLockers_fld = (*env)->GetFieldID
874 (env, mutex_class, "potentialLockers", "I");
875 if ( ! mutex_class )
877 BROKEN (env, "cannot find GThreadMutex.potentialLockers");
878 return initialized = -1;
881 if (! (mutex_lockForPotentialLockers_fld = (*env)->GetFieldID
882 (env, mutex_class, "lockForPotentialLockers", "Ljava/lang/Object;")))
884 BROKEN (env, "cannot find GThreadMutex.lockForPotentialLockers");
885 return initialized = -1;
889 /* java.lang.Thread */
890 if (! (lcl_class = (*env)->FindClass (env, "java/lang/Thread")))
892 BROKEN (env, "cannot find java.lang.Thread");
893 return initialized = -1;
896 /* Pin it down. */
897 thread_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
898 DELETE_LOCAL_REF (env, lcl_class);
899 if (!thread_class)
901 BROKEN (env, "Cannot get a global reference to java.lang.Thread");
902 return initialized = -1;
905 thread_current_mth =
906 (*env)->GetStaticMethodID (env, thread_class, "currentThread",
907 "()Ljava/lang/Thread;");
908 if (!thread_current_mth)
910 BROKEN (env, "cannot find Thread.currentThread() method");
911 return initialized = -1;
914 thread_equals_mth =
915 (*env)->GetMethodID (env, thread_class, "equals", "(Ljava/lang/Object;)Z");
916 if (!thread_equals_mth)
918 BROKEN (env, "cannot find Thread.equals() method");
919 return initialized = -1;
922 thread_join_mth = (*env)->GetMethodID (env, thread_class, "join", "()V");
923 if (!thread_join_mth)
925 BROKEN (env, "cannot find Thread.join() method");
926 return initialized = -1;
929 thread_stop_mth = (*env)->GetMethodID (env, thread_class, "stop", "()V");
930 if ( ! thread_stop_mth )
932 BROKEN (env, "cannot find Thread.stop() method");
933 return initialized = -1;
936 thread_setPriority_mth =
937 (*env)->GetMethodID (env, thread_class, "setPriority", "(I)V");
938 if ( ! thread_setPriority_mth )
940 BROKEN (env, "cannot find Thread.setPriority() method");
941 return initialized = -1;
944 thread_yield_mth =
945 (*env)->GetStaticMethodID (env, thread_class, "yield", "()V");
946 if ( ! thread_yield_mth )
948 BROKEN (env, "cannot find Thread.yield() method");
949 return initialized = -1;
952 /* java.lang.ThreadLocal */
953 lcl_class = (*env)->FindClass (env, "java/lang/ThreadLocal");
954 if ( ! lcl_class )
956 BROKEN (env, "cannot find class java.lang.ThreadLocal");
957 return initialized = -1;
960 /* Pin it down. */
961 threadlocal_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
962 DELETE_LOCAL_REF (env, lcl_class);
963 if ( ! threadlocal_class )
965 BROKEN (env, "Cannot get a global reference to java.lang.ThreadLocal");
966 return initialized = -1;
969 threadlocal_ctor = (*env)->GetMethodID (env, threadlocal_class,
970 "<init>", "()V");
971 if ( ! threadlocal_ctor )
973 BROKEN (env, "cannot find ThreadLocal.<init>()V");
974 return initialized = -1;
977 threadlocal_get_mth = (*env)->GetMethodID (env, threadlocal_class,
978 "get", "()Ljava/lang/Object;");
979 if ( ! threadlocal_get_mth )
981 BROKEN (env, "cannot find java.lang.ThreadLocal.get()Object");
982 return initialized = -1;
985 threadlocal_set_mth = (*env)->GetMethodID (env, threadlocal_class,
986 "set", "(Ljava/lang/Object;)V");
987 if ( ! threadlocal_set_mth )
989 BROKEN (env, "cannot find ThreadLocal.set(Object)V");
990 return initialized = -1;
993 /* java.lang.Long */
994 lcl_class = (*env)->FindClass (env, "java/lang/Long");
995 if ( ! lcl_class )
997 BROKEN (env, "cannot find class java.lang.Long");
998 return initialized = -1;
1001 /* Pin it down. */
1002 long_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
1003 DELETE_LOCAL_REF (env, lcl_class);
1004 if (!long_class)
1006 BROKEN (env, "Cannot get a global reference to java.lang.Long");
1007 return initialized = -1;
1010 long_ctor = (*env)->GetMethodID (env, long_class, "<init>", "(J)V");
1011 if (!long_ctor)
1013 BROKEN (env, "cannot find method java.lang.Long.<init>(J)V");
1014 return initialized = -1;
1017 long_longValue_mth =
1018 (*env)->GetMethodID (env, long_class, "longValue", "()J");
1019 if (!long_longValue_mth)
1021 BROKEN (env, "cannot find method java.lang.Long.longValue()J");
1022 return initialized = -1;
1026 /* GThreadNativeMethodRunner */
1027 lcl_class =
1028 (*env)->FindClass (env,
1029 "gnu/java/awt/peer/gtk/GThreadNativeMethodRunner");
1030 if ( ! lcl_class )
1032 BROKEN (env,
1033 "cannot find gnu.java.awt.peer.gtk.GThreadNativeMethodRunner");
1034 return initialized = -1;
1037 /* Pin it down. */
1038 runner_class = (jclass) (*env)->NewGlobalRef (env, lcl_class);
1039 DELETE_LOCAL_REF (env, lcl_class);
1040 if (!runner_class)
1042 BROKEN (env,
1043 "Cannot get a global reference to the class GThreadNativeMethodRunner");
1044 return initialized = -1;
1047 runner_ctor = (*env)->GetMethodID (env, runner_class, "<init>", "(JJZ)V");
1048 if ( ! runner_ctor )
1050 BROKEN (env,
1051 "cannot find method GThreadNativeMethodRunner.<init>(JJZ)");
1052 return initialized = -1;
1055 runner_start_mth = (*env)->GetMethodID (env, runner_class, "start", "()V");
1056 if ( ! runner_start_mth )
1058 BROKEN (env, "cannot find method GThreadNativeMethodRunner.start()V");
1059 return initialized = -1;
1063 runner_threadToThreadID_mth =
1064 (*env)->GetStaticMethodID (env, runner_class,
1065 "threadToThreadID", "(Ljava/lang/Thread;)I");
1066 if ( ! runner_threadToThreadID_mth )
1068 BROKEN (env,
1069 "cannot find method GThreadNativeMethodRunner.threadToThreadID(java.lang.Thread)I");
1070 return initialized = -1;
1074 runner_threadIDToThread_mth =
1075 (*env)->GetStaticMethodID (env, runner_class,
1076 "threadIDToThread", "(I)Ljava/lang/Thread;");
1077 if ( ! runner_threadIDToThread_mth )
1079 BROKEN (env,
1080 "cannot find method GThreadNativeMethodRunner.threadIDToThread(I)java.lang.Thread");
1081 return initialized = -1;
1085 runner_deRegisterJoinable_mth =
1086 (*env)->GetStaticMethodID (env, runner_class, "deRegisterJoinable",
1087 "(Ljava/lang/Thread;)V");
1088 if (!runner_deRegisterJoinable_mth)
1090 BROKEN (env,
1091 "cannot find method GThreadNativeMethodRunner.deRegisterJoinable(java.lang.Thread)V");
1092 return initialized = -1;
1096 /* java.lang.InterruptedException */
1097 lcl_class = (*env)->FindClass (env, "java/lang/InterruptedException");
1098 if ( ! lcl_class )
1100 BROKEN (env, "cannot find class java.lang.InterruptedException");
1101 return initialized = -1;
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)
1109 BROKEN (env, "Cannot make a global reference"
1110 " to java.lang.InterruptedException");
1111 return initialized = -1;
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));
1122 return initialized = 1;
1129 /************************************************************************/
1130 /* Utilities to allocate and free java.lang.Objects */
1131 /************************************************************************/
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?).
1137 static jobject
1138 allocatePlainObject (JNIEnv * env)
1140 jobject lcl_obj, global_obj;
1142 lcl_obj = (*env)->NewObject (env, obj_class, obj_ctor);
1143 if (!lcl_obj)
1145 BROKEN (env, "cannot allocate object");
1146 return NULL;
1149 global_obj = (*env)->NewGlobalRef (env, lcl_obj);
1150 DELETE_LOCAL_REF (env, lcl_obj);
1151 if (!global_obj)
1153 NEW_BROKEN (env, "cannot make global ref for a new plain Java object");
1154 /* Deliberate fall-through */
1157 return global_obj;
1160 /* Frees any Java object given a global ref (isn't C fun?) */
1161 static void
1162 freeObject (JNIEnv * env, jobject obj)
1164 if (obj)
1166 (*env)->DeleteGlobalRef (env, obj);
1167 /* DeleteGlobalRef can never fail */
1172 /************************************************************************/
1173 /* Utilities to allocate and free Java mutexes */
1174 /************************************************************************/
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?).
1180 * Free this with freeObject()
1182 static jobject
1183 allocateMutexObject (JNIEnv * env)
1185 jobject lcl_obj, global_obj;
1187 lcl_obj = (*env)->NewObject (env, mutex_class, mutex_ctor);
1188 if (!lcl_obj)
1190 BROKEN (env, "cannot allocate a GThreadMutex");
1191 return NULL;
1194 global_obj = (*env)->NewGlobalRef (env, lcl_obj);
1195 DELETE_LOCAL_REF (env, lcl_obj);
1196 if (!global_obj)
1198 NEW_BROKEN (env, "cannot make global ref");
1199 /* Deliberate fallthrough */
1202 return global_obj;
1206 /************************************************************************/
1207 /* Locking code */
1208 /************************************************************************/
1210 /* Lock a Java object */
1211 #define ENTER_MONITOR(env, m) \
1212 enterMonitor(env, m, G_STRINGIFY(m))
1214 /* Return -1 on failure, 0 on success. */
1215 static int
1216 enterMonitor (JNIEnv * env, jobject monitorObj, const char monName[])
1218 if (TRACE_MONITORS)
1219 tracing (" <MonitorEnter(%s)>", monName);
1220 assert (monitorObj);
1221 if ((*env)->MonitorEnter (env, monitorObj) < 0)
1223 BROKEN (env, "cannot enter monitor");
1224 return -1;
1226 return 0;
1230 /* Unlock a Java object */
1231 #define EXIT_MONITOR(env, m) \
1232 exitMonitor(env, m, G_STRINGIFY(m))
1234 static int
1235 exitMonitor (JNIEnv * env, jobject mutexObj, const char monName[])
1237 if (TRACE_MONITORS)
1238 tracing (" <MonitorExit(%s)>", monName);
1239 assert (mutexObj);
1240 if ((*env)->MonitorExit (env, mutexObj) < 0)
1242 BROKEN (env, "cannot exit monitor ");
1243 return -1;
1245 return 0;
1249 /************************************************************************/
1250 /* Miscellaneous utilities */
1251 /************************************************************************/
1253 /* Get the Java Thread object that corresponds to a particular thread ID.
1254 A negative thread Id gives us a null object.
1256 Returns a local reference.
1258 static jobject
1259 getThreadFromThreadID (JNIEnv * env, gpointer gThreadID)
1261 jint threadNum = (jint) gThreadID;
1262 jobject thread;
1264 if (threadNum < 0)
1266 NEW_BROKEN (env, "getThreadFromThreadID asked to look up"
1267 " a negative thread index");
1268 return NULL;
1271 thread = (*env)->CallStaticObjectMethod
1272 (env, runner_class, runner_threadIDToThread_mth, threadNum);
1274 if (MAYBE_BROKEN (env, "cannot get Thread for threadID "))
1275 return NULL;
1277 return thread;
1280 /** Return the unique threadID of THREAD.
1282 Error handling: Return (gpointer) -1 on all failures,
1283 and propagate an exception.
1285 static gpointer
1286 getThreadIDFromThread (JNIEnv * env, jobject thread)
1288 jint threadNum;
1290 if (ENABLE_EXPENSIVE_ASSERTIONS)
1291 assert ((*env)->IsInstanceOf (env, thread, thread_class));
1293 HIDE_OLD_TROUBLE (env);
1295 threadNum = (*env)->CallStaticIntMethod
1296 (env, runner_class, runner_threadToThreadID_mth, thread);
1298 if (MAYBE_BROKEN (env, "cannot get ThreadID for a Thread "))
1300 threadNum = -1;
1301 goto done;
1305 SHOW_OLD_TROUBLE ();
1307 done:
1308 return (gpointer) threadNum;
1312 /************************************************************************/
1313 /* The Actual JNI functions that we pass to the function vector. */
1314 /************************************************************************/
1317 /************************************************************************/
1318 /* Mutex Functions */
1319 /************************************************************************/
1321 /*** Mutex Utilities ****/
1322 struct mutexObj_cache
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. */
1330 /* Initialize the cache of sub-locks for a particular mutex object.
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.)
1337 Guaranteed to leave all fields of the cache initialized, even if only to
1338 zero.
1340 static int
1341 populate_mutexObj_cache (JNIEnv * env, jobject mutexObj,
1342 struct mutexObj_cache *mcache)
1344 mcache->lockObj = mutexObj; /* the mutexObj is its own lock. */
1345 assert (mcache->lockObj);
1347 mcache->lockForPotentialLockersObj = (*env)->GetObjectField
1348 (env, mutexObj, mutex_lockForPotentialLockers_fld);
1349 /* GetObjectField can never fail. */
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);
1355 return 0;
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)
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;
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)
1374 jint potentialLockers;
1376 if (ENTER_MONITOR (env, mcache->lockForPotentialLockersObj))
1377 return -1;
1379 assert(mutexObj);
1380 potentialLockers =
1381 (*env)->GetIntField (env, mutexObj, mutex_potentialLockers_fld);
1382 /* GetIntField() never fails. */
1384 ++potentialLockers;
1386 (*env)->SetIntField
1387 (env, mutexObj, mutex_potentialLockers_fld, potentialLockers);
1389 if (EXIT_MONITOR (env, mcache->lockForPotentialLockersObj))
1390 return -1;
1392 if (ENTER_MONITOR (env, mcache->lockObj))
1393 return -1;
1395 SHOW_OLD_TROUBLE ();
1397 return 0;
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.
1404 Returns -1 on error, 0 on success. */
1405 static int
1406 mutexObj_unlock (JNIEnv * env, jobject mutexObj,
1407 struct mutexObj_cache *mcache)
1409 jint potentialLockers;
1410 int ret = -1; /* assume failure until we suceed. */
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;
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;
1423 potentialLockers = (*env)->GetIntField
1424 (env, mutexObj, mutex_potentialLockers_fld);
1425 /* GetIntField never fails */
1427 assert (potentialLockers >= 1);
1428 --potentialLockers;
1430 (*env)->SetIntField
1431 (env, mutexObj, mutex_potentialLockers_fld, potentialLockers);
1432 /* Never fails, so the JNI book says. */
1434 /* Clean up. */
1435 if (EXIT_MONITOR (env, mcache->lockForPotentialLockersObj) < 0)
1436 goto done;
1437 ret = 0;
1439 done:
1440 return ret;
1443 /*** Mutex Implementations ****/
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)
1451 jobject mutexObj;
1452 JNIEnv *env;
1453 union env_union e;
1455 if (TRACE_API_CALLS)
1456 tracing ("mutex_new_jni_impl()");
1458 e.jni_env = &env;
1459 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
1461 if (setup_cache (env) < 0)
1463 mutexObj = NULL;
1464 goto done;
1467 mutexObj = allocateMutexObject (env);
1469 done:
1470 if (TRACE_API_CALLS)
1471 tracing (" ==> %p \n", mutexObj);
1473 return (GMutex *) mutexObj;
1477 /* Lock a mutex. */
1478 static void
1479 mutex_lock_jni_impl (GMutex * mutex)
1481 struct mutexObj_cache mcache;
1482 jobject mutexObj = (jobject) mutex;
1483 JNIEnv *env;
1484 union env_union e;
1486 if (TRACE_API_CALLS)
1487 tracing ("mutex_lock_jni_impl( mutexObj = %p )", mutexObj);
1489 assert (mutexObj);
1490 e.jni_env = &env;
1491 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
1493 if (setup_cache (env) < 0)
1494 goto done;
1496 HIDE_OLD_TROUBLE (env);
1498 if (populate_mutexObj_cache (env, mutexObj, &mcache) < 0)
1499 goto done;
1501 mutexObj_lock (env, mutexObj, &mcache);
1502 /* No need to error check; we've already reported it in any case. */
1504 done:
1505 clean_mutexObj_cache (env, &mcache);
1506 if (TRACE_API_CALLS)
1507 tracing (" ==> VOID \n");
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)
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;
1523 if (TRACE_API_CALLS)
1524 tracing ("mutex_trylock_jni_impl(mutexObj=%p)", mutexObj);
1526 assert (mutexObj);
1528 e.jni_env = &env;
1529 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
1530 if (setup_cache (env) < 0)
1531 goto done;
1532 HIDE_OLD_TROUBLE (env);
1534 if (populate_mutexObj_cache (env, mutexObj, &mcache) < 0)
1535 goto done;
1537 if (ENTER_MONITOR (env, mcache.lockForPotentialLockersObj))
1538 goto done;
1540 potentialLockers = (*env)->GetIntField
1541 (env, mutexObj, mutex_potentialLockers_fld);
1543 assert (potentialLockers >= 0);
1545 if (potentialLockers)
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;
1554 /* Guaranteed not to block. */
1555 if (ENTER_MONITOR (env, mcache.lockObj))
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;
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 */
1571 ret = TRUE; /* We have the lock. */
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. */
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;
1587 /* Unlock a mutex. */
1588 static void
1589 mutex_unlock_jni_impl (GMutex * gmutex)
1591 jobject mutexObj = (jobject) gmutex;
1592 struct mutexObj_cache mcache;
1593 JNIEnv *env;
1594 union env_union e;
1596 if (TRACE_API_CALLS)
1597 tracing ("mutex_unlock_jni_impl(mutexObj=%p)", mutexObj);
1599 e.jni_env = &env;
1600 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
1601 if (setup_cache (env) < 0)
1602 goto done;
1603 HIDE_OLD_TROUBLE (env);
1605 assert (mutexObj);
1607 if ( populate_mutexObj_cache (env, mutexObj, &mcache) < 0)
1608 goto done;
1610 (void) mutexObj_unlock (env, mutexObj, &mcache);
1612 SHOW_OLD_TROUBLE ();
1614 done:
1615 clean_mutexObj_cache (env, &mcache);
1616 if (TRACE_API_CALLS)
1617 tracing (" ==> VOID\n");
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)
1627 jobject mutexObj = (jobject) mutex;
1628 JNIEnv *env;
1629 union env_union e;
1631 e.jni_env = &env;
1632 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
1634 if (TRACE_API_CALLS)
1635 tracing ("mutex_free_jni_impl(%p)", mutexObj);
1637 freeObject (env, mutexObj);
1639 if (TRACE_API_CALLS)
1640 tracing (" ==> VOID\n");
1646 /************************************************************************/
1647 /* Condition variable code */
1648 /************************************************************************/
1650 /* Create a new condition variable. This is a java.lang.Object for us. */
1651 static GCond *
1652 cond_new_jni_impl (void)
1654 jobject condObj;
1655 JNIEnv *env;
1656 union env_union e;
1658 if (TRACE_API_CALLS)
1659 tracing ("mutex_free_jni_impl()");
1661 e.jni_env = &env;
1662 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
1664 condObj = allocatePlainObject (env);
1666 if (TRACE_API_CALLS)
1667 tracing (" ==> %p\n", condObj);
1669 return (GCond *) condObj;
1672 /* Signal on a condition variable. This is simply calling Object.notify
1673 * for us.
1675 static void
1676 cond_signal_jni_impl (GCond * gcond)
1678 JNIEnv *env;
1679 union env_union e;
1680 jobject condObj = (jobject) gcond;
1682 if (TRACE_API_CALLS)
1683 tracing ("cond_signal_jni_impl(condObj = %p)", condObj);
1685 e.jni_env = &env;
1686 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
1687 if (setup_cache (env) < 0)
1688 goto done;
1689 HIDE_OLD_TROUBLE (env);
1691 assert (condObj);
1693 /* Must have locked an object to call notify */
1694 if (ENTER_MONITOR (env, condObj))
1695 goto done;
1697 (*env)->CallVoidMethod (env, condObj, obj_notify_mth);
1698 if (MAYBE_BROKEN (env, "cannot signal mutex with Object.notify()"))
1700 if (EXIT_MONITOR (env, condObj))
1701 BADLY_BROKEN1 ("Failed to unlock a monitor; the VM may deadlock.");
1702 goto done;
1705 EXIT_MONITOR (env, condObj);
1707 SHOW_OLD_TROUBLE ();
1709 done:
1710 if (TRACE_API_CALLS)
1711 tracing (" ==> VOID\n");
1714 /* Broadcast to all waiting on a condition variable. This is simply
1715 * calling Object.notifyAll for us.
1717 static void
1718 cond_broadcast_jni_impl (GCond * gcond)
1720 jobject condObj = (jobject) gcond;
1721 JNIEnv *env;
1722 union env_union e;
1724 if (TRACE_API_CALLS)
1725 tracing ("cond_broadcast_jni_impl(condObj=%p)", condObj);
1727 e.jni_env = &env;
1728 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
1729 if (setup_cache (env) < 0)
1730 goto done;
1731 HIDE_OLD_TROUBLE (env);
1733 assert (condObj);
1734 /* Must have locked an object to call notifyAll */
1735 if (ENTER_MONITOR (env, condObj))
1736 goto done;
1738 (*env)->CallVoidMethod (env, condObj, obj_notifyall_mth);
1739 if (MAYBE_BROKEN (env, "cannot broadcast to mutex with Object.notify()"))
1741 EXIT_MONITOR (env, condObj);
1742 goto done;
1745 EXIT_MONITOR (env, condObj);
1747 SHOW_OLD_TROUBLE ();
1749 done:
1750 if (TRACE_API_CALLS)
1751 tracing (" ==> VOID\n");
1755 /* Wait on a condition variable. For us, this simply means calling
1756 * Object.wait.
1758 * Throws a Java exception on trouble; may leave the mutexes set arbitrarily.
1759 * XXX TODO: Further improve error recovery.
1761 static void
1762 cond_wait_jni_impl (GCond * gcond, GMutex * gmutex)
1764 struct mutexObj_cache cache;
1765 jobject condObj = (jobject) gcond;
1766 jobject mutexObj = (jobject) gmutex;
1767 JNIEnv *env;
1768 union env_union e;
1770 if (TRACE_API_CALLS)
1771 tracing ("cond_wait_jni_impl(condObj=%p, mutexObj=%p)",
1772 condObj, mutexObj);
1774 e.jni_env = &env;
1775 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
1776 if (setup_cache (env) < 0)
1777 goto done;
1778 HIDE_OLD_TROUBLE (env);
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;
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;
1791 (*env)->CallVoidMethod (env, condObj, obj_wait_mth);
1792 if (MAYBE_BROKEN (env, "cannot wait on condObj"))
1794 EXIT_MONITOR (env, condObj); /* ignore err checking */
1795 goto done;
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;
1803 EXIT_MONITOR (env, condObj);
1805 SHOW_OLD_TROUBLE ();
1807 done:
1808 if (TRACE_API_CALLS)
1809 tracing (" ==> VOID\n");
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.
1818 * We return FALSE if we timed out. Return TRUE if the condition was
1819 * signalled first, before we timed out.
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.
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.
1830 static gboolean
1831 cond_timed_wait_jni_impl (GCond * gcond, GMutex * gmutex, GTimeVal * end_time)
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;
1844 if (TRACE_API_CALLS)
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);
1853 e.jni_env = &env;
1854 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
1855 if (setup_cache (env) < 0)
1856 goto done;
1857 HIDE_OLD_TROUBLE (env);
1859 time_millisec = end_time->tv_sec * 1000 + end_time->tv_usec / 1000;
1860 time_nanosec = 1000 * (end_time->tv_usec % 1000);
1862 /* Must have locked an object to call wait */
1863 if (ENTER_MONITOR (env, condObj) < 0)
1864 goto done;
1866 if (mutexObj_unlock (env, mutexObj, &cache) < 0)
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;
1875 (*env)->CallVoidMethod (env, condObj, obj_wait_nanotime_mth,
1876 time_millisec, time_nanosec);
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);
1882 if ( ! cause )
1884 condRaised = TRUE; /* condition was signalled */
1886 else if ((*env)->IsInstanceOf (env, cause, interrupted_exception_class))
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. */
1894 else
1896 interrupted = FALSE; /* Trouble, but not because of
1897 InterruptedException. Assume the condition
1898 was not raised. */
1899 /* Leave condRaised set to FALSE */
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)
1909 cause = (*env)->ExceptionOccurred (env);
1910 assert (cause);
1913 if (EXIT_MONITOR (env, condObj) && !cause)
1915 cause = (*env)->ExceptionOccurred (env);
1916 assert (cause);
1919 if (cause) /* Raise the first cause. */
1921 BROKEN_CAUSE (env, cause, "error in timed wait or during its cleanup");
1922 goto done;
1925 SHOW_OLD_TROUBLE ();
1927 done:
1928 if (TRACE_API_CALLS)
1929 tracing (" ==> condRaised = %s\n", condRaised ? "TRUE" : "FALSE");
1930 return condRaised;
1934 /* Free a condition variable. (isn't C fun?). Can not fail. */
1935 static void
1936 cond_free_jni_impl (GCond * cond)
1938 jobject condObj = (jobject) cond;
1939 JNIEnv *env;
1940 union env_union e;
1942 if (TRACE_API_CALLS)
1943 tracing ("cond_free_jni_impl(condObj = %p)", condObj);
1944 e.jni_env = &env;
1945 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
1947 freeObject (env, condObj);
1949 if (TRACE_API_CALLS)
1950 tracing (" ==> VOID\n");
1954 /************************************************************************/
1955 /* Thread-local data code */
1956 /************************************************************************/
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.
1962 * We will throw a Java exception and return NULL in case of failure.
1964 static GPrivate *
1965 private_new_jni_impl (GDestroyNotify notify __attribute__ ((unused)))
1967 JNIEnv *env;
1968 union env_union e;
1969 jobject lcl_key;
1970 jobject global_key;
1971 GPrivate *gkey = NULL; /* Error return code */
1973 if (TRACE_API_CALLS)
1974 tracing ("private_new_jni_impl()");
1976 e.jni_env = &env;
1977 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
1978 if (setup_cache (env) < 0)
1979 goto done;
1980 HIDE_OLD_TROUBLE (env);
1982 lcl_key = (*env)->NewObject (env, threadlocal_class, threadlocal_ctor);
1983 if ( ! lcl_key )
1985 BROKEN (env, "cannot allocate a ThreadLocal");
1986 goto done;
1989 global_key = ((*env)->NewGlobalRef (env, lcl_key));
1990 DELETE_LOCAL_REF (env, lcl_key);
1991 if ( ! global_key)
1993 NEW_BROKEN (env, "cannot create a GlobalRef to a new ThreadLocal");
1994 goto done;
1997 gkey = (GPrivate *) global_key;
1998 SHOW_OLD_TROUBLE ();
2000 done:
2001 if (TRACE_API_CALLS)
2002 tracing (" ==> %p\n", (void *) gkey);
2004 return gkey;
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.)
2011 static gpointer
2012 private_get_jni_impl (GPrivate * gkey)
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 */
2020 jlong val;
2022 if (TRACE_API_CALLS)
2023 tracing ("private_get_jni_impl(keyObj=%p)", keyObj);
2025 e.jni_env = &env;
2026 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
2027 if (setup_cache (env) < 0)
2028 goto done;
2029 HIDE_OLD_TROUBLE (env);
2031 val_wrapper = (*env)->CallObjectMethod (env, keyObj, threadlocal_get_mth);
2032 if (MAYBE_BROKEN (env, "cannot find thread-local object"))
2033 goto done;
2035 if (! val_wrapper )
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;
2046 val = (*env)->CallLongMethod (env, val_wrapper, long_longValue_mth);
2048 if (MAYBE_BROKEN (env, "cannot get thread local value"))
2049 goto done;
2051 thread_specific_data = (gpointer) (intptr_t) val;
2053 /* Only re-raise the old pending exception if a new one hasn't come along to
2054 supersede it. */
2055 SHOW_OLD_TROUBLE ();
2057 done:
2059 if (TRACE_API_CALLS)
2060 tracing (" ==> %p\n", thread_specific_data);
2062 return thread_specific_data;
2065 /* Set this thread's value for a thread-local key. This is simply
2066 * ThreadLocal.set() for us.
2068 static void
2069 private_set_jni_impl (GPrivate * gkey, gpointer thread_specific_data)
2071 JNIEnv *env;
2072 union env_union e;
2073 jobject val_wrapper;
2074 jobject keyObj = (jobject) gkey;
2077 if (TRACE_API_CALLS)
2078 tracing ("private_set_jni_impl(keyObj=%p, thread_specific_data=%p)",
2079 keyObj, thread_specific_data);
2081 e.jni_env = &env;
2082 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
2083 if (setup_cache (env) < 0)
2084 goto done;
2085 HIDE_OLD_TROUBLE (env);
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.
2094 val_wrapper = (*env)->NewObject (env, long_class, long_ctor,
2095 (jlong) (intptr_t) thread_specific_data);
2096 if ( ! val_wrapper )
2098 BROKEN (env, "cannot create a java.lang.Long");
2099 goto done;
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;
2108 SHOW_OLD_TROUBLE ();
2109 done:
2110 if (TRACE_API_CALLS)
2111 tracing (" ==> VOID\n");
2115 /** Create an object of type gnu.java.awt.peer.gtk.GThreadNativeMethodRunner.
2116 Run it.
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.
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.
2125 Error handling:
2127 To quote from the glib guide:
2128 "GError should only be used to report recoverable runtime errors, never
2129 to report programming errors."
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.
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.
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)))
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 */
2166 if (TRACE_API_CALLS)
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);
2175 e.jni_env = &env;
2176 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
2177 if (setup_cache (env) < 0)
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;
2184 HIDE_OLD_TROUBLE (env);
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 )
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;
2203 if (threadObj_set_priority (env, newThreadObj, gpriority) < 0)
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;
2212 (*env)->CallVoidMethod (env, runner_class, runner_start_mth);
2214 if (MAYBE_BROKEN (env, "starting a new thread failed"))
2216 *(gpointer *) threadIDp = NULL;
2217 /* The only exception Thread.start() throws is
2218 IllegalStateException. And that would indicate a programming error.
2220 So there are no situations such that G_THREAD_ERROR_AGAIN would be
2221 OK.
2223 So, we don't use g_set_error() here to perform any error reporting.
2225 goto done;
2228 threadID = getThreadIDFromThread (env, newThreadObj);
2230 *(gpointer *) threadIDp = threadID;
2231 SHOW_OLD_TROUBLE ();
2233 done:
2234 if (TRACE_API_CALLS)
2235 tracing (" ==> (threadID = %p) \n", threadID);
2239 /* Wraps a call to g_thread_yield. */
2240 static void
2241 thread_yield_jni_impl (void)
2243 JNIEnv *env;
2244 union env_union e;
2246 if (TRACE_API_CALLS)
2247 tracing ("thread_yield_jni_impl()");
2249 e.jni_env = &env;
2250 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
2251 if (setup_cache (env) < 0)
2252 goto done;
2253 HIDE_OLD_TROUBLE (env);
2255 (*env)->CallStaticVoidMethod (env, thread_class, thread_yield_mth);
2256 if (MAYBE_BROKEN (env, "Thread.yield() failed"))
2257 goto done;
2259 SHOW_OLD_TROUBLE ();
2261 done:
2262 if (TRACE_API_CALLS)
2263 tracing (" ==> VOID\n");
2267 static void
2268 thread_join_jni_impl (gpointer threadID)
2270 JNIEnv *env;
2271 union env_union e;
2272 jobject threadObj = NULL;
2274 if ( TRACE_API_CALLS )
2275 tracing ("thread_join_jni_impl(threadID=%p) ", threadID);
2277 e.jni_env = &env;
2278 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
2279 if (setup_cache (env) < 0)
2280 goto done;
2281 HIDE_OLD_TROUBLE (env);
2283 threadObj = getThreadFromThreadID (env, threadID);
2284 if ( ! threadObj ) /* Already reported with BROKEN */
2285 goto done;
2287 (*env)->CallVoidMethod (env, threadObj, thread_join_mth);
2288 if (MAYBE_BROKEN (env, "Thread.join() failed"))
2289 goto done;
2292 (*env)->CallStaticVoidMethod
2293 (env, runner_class, runner_deRegisterJoinable_mth, threadObj);
2294 if (MAYBE_BROKEN (env, "Thread.deRegisterJoinableThread() failed"))
2295 goto done;
2297 SHOW_OLD_TROUBLE ();
2299 done:
2300 DELETE_LOCAL_REF (env, threadObj);
2301 if (TRACE_API_CALLS)
2302 tracing (" ==> VOID \n");
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.
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)
2318 JNIEnv *env;
2319 union env_union e;
2320 jobject this_thread;
2322 if (TRACE_API_CALLS)
2323 tracing ("thread_exit_jni_impl() ");
2325 e.jni_env = &env;
2326 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
2327 if (setup_cache (env) < 0)
2328 goto done;
2330 HIDE_OLD_TROUBLE (env);
2332 this_thread = (*env)->
2333 CallStaticObjectMethod (env, thread_class, thread_current_mth);
2335 if ( ! this_thread )
2337 BROKEN (env, "cannot get current thread");
2338 goto done;
2341 (*env)->CallVoidMethod (env, this_thread, thread_stop_mth);
2342 if (MAYBE_BROKEN (env, "cannot call Thread.stop() on current thread"))
2343 goto done;
2345 SHOW_OLD_TROUBLE ();
2347 done:
2348 if (TRACE_API_CALLS)
2349 tracing (" ==> VOID \n");
2353 /* Translate a GThreadPriority to a Java priority level. */
2354 static jint
2355 javaPriorityLevel (GThreadPriority priority)
2357 /* We have these fields in java.lang.Thread to play with:
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.
2364 We get these from the header file generated by javah, even though they're
2365 documented as being 1, 5, and 10.
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;
2374 switch (priority)
2376 case G_THREAD_PRIORITY_LOW:
2377 return minJPri;
2378 break;
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;
2388 case G_THREAD_PRIORITY_HIGH:
2389 return (normJPri + maxJPri) / 2;
2390 break;
2392 case G_THREAD_PRIORITY_URGENT:
2393 return maxJPri;
2394 break;
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.
2403 static void
2404 thread_set_priority_jni_impl (gpointer gThreadID, GThreadPriority gpriority)
2406 jobject threadObj = NULL;
2407 JNIEnv *env;
2408 union env_union e;
2410 if (TRACE_API_CALLS)
2411 tracing ("thread_set_priority_jni_impl(gThreadID=%p, gpriority = %u) ",
2412 gThreadID, gpriority);
2414 e.jni_env = &env;
2415 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
2417 if (setup_cache (env) < 0)
2418 goto done;
2420 HIDE_OLD_TROUBLE (env);
2423 threadObj = getThreadFromThreadID (env, gThreadID);
2424 if ( ! threadObj) /* Reported with BROKEN already. */
2425 goto done;
2427 if (threadObj_set_priority (env, threadObj, gpriority))
2428 goto done;
2430 SHOW_OLD_TROUBLE ();
2432 done:
2433 DELETE_LOCAL_REF (env, threadObj);
2435 if (TRACE_API_CALLS)
2436 tracing (" ==> VOID\n");
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.
2444 -1 on failure, 0 on success. */
2445 static int
2446 threadObj_set_priority (JNIEnv * env, jobject threadObj,
2447 GThreadPriority gpriority)
2449 jint javaPriority = javaPriorityLevel (gpriority);
2450 (*env)->CallVoidMethod (env, threadObj, thread_setPriority_mth,
2451 javaPriority);
2452 return MAYBE_BROKEN (env, "Thread.setPriority() failed");
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)
2463 JNIEnv *env;
2464 union env_union e;
2465 jobject this_thread;
2466 gpointer my_threadID;
2468 if (TRACE_API_CALLS)
2469 tracing ("thread_self_jni_impl(my_thread_IDp=%p)", my_thread_IDp);
2471 e.jni_env = &env;
2472 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
2474 if (setup_cache (env) < 0)
2475 return;
2477 HIDE_OLD_TROUBLE (env);
2479 this_thread = (*env)->
2480 CallStaticObjectMethod (env, thread_class, thread_current_mth);
2481 if (! this_thread )
2483 BROKEN (env, "cannot get current thread");
2484 my_threadID = NULL;
2485 goto done;
2488 my_threadID = getThreadIDFromThread (env, this_thread);
2489 SHOW_OLD_TROUBLE ();
2491 done:
2492 if (TRACE_API_CALLS)
2493 tracing (" ==> (my_threadID = %p) \n", my_threadID);
2495 *(gpointer *) my_thread_IDp = my_threadID;
2499 static gboolean
2500 thread_equal_jni_impl (gpointer thread1, gpointer thread2)
2502 JNIEnv *env;
2503 union env_union e;
2505 gpointer threadID1 = *(gpointer *) thread1;
2506 gpointer threadID2 = *(gpointer *) thread2;
2508 jobject thread1_obj = NULL;
2509 jobject thread2_obj = NULL;
2510 gboolean ret;
2512 if (TRACE_API_CALLS)
2513 tracing ("thread_equal_jni_impl(threadID1=%p, threadID2=%p)",
2514 threadID1, threadID2);
2516 e.jni_env = &env;
2517 (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
2518 if (setup_cache (env) < 0)
2520 ret = FALSE; /* what is safer? We really don't ever want
2521 to return from here. */
2522 goto done;
2525 HIDE_OLD_TROUBLE (env);
2526 thread1_obj = getThreadFromThreadID (env, threadID1);
2527 thread2_obj = getThreadFromThreadID (env, threadID2);
2529 ret = (*env)->CallBooleanMethod (env, thread1_obj,
2530 thread_equals_mth, thread2_obj);
2532 if (MAYBE_BROKEN (env, "Thread.equals() failed"))
2534 ret = FALSE;
2535 goto done;
2538 SHOW_OLD_TROUBLE ();
2541 done:
2542 DELETE_LOCAL_REF (env, thread1_obj);
2543 DELETE_LOCAL_REF (env, thread2_obj);
2545 if (TRACE_API_CALLS)
2546 tracing (" ==> %s\n", ret ? "TRUE" : "FALSE");
2548 return ret;
2554 /************************************************************************/
2555 /* GLIB interface */
2556 /************************************************************************/
2558 /* set of function pointers to give to glib. */
2559 GThreadFunctions 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 */
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: */