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)
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., 51 Franklin Street, Fifth Floor, Boston, MA
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
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 /************************************************************************/
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
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
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
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:
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 )
116 /************************************************************************/
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
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
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
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
165 #define DIE_IF_BADLY_BROKEN 1 /* DIE_IF_BROKEN implies DIE_IF_BADLY_BROKEN */
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. */
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
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 /************************************************************************/
219 /************************************************************************/
221 #if defined HAVE_STDINT_H
222 #include <stdint.h> /* provides intptr_t */
223 #elif defined HAVE_INTTYPES_H
224 #include <inttypes.h>
226 #include <stdarg.h> /* va_list */
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
239 #ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY
240 #define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY 5
242 #ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY
243 #define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY 10
246 /* The VM handle. This is set in
247 Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit */
248 JavaVM
*cp_gtk_the_vm
;
250 /* Unions used for type punning. */
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
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.
328 fatalMsg (const char fmt
[], ...)
332 vfprintf (stderr
, fmt
, ap
);
334 fputs ("\nAborting execution\n", stderr
);
340 criticalMsg (const char fmt
[], ...)
344 vfprintf (stderr
, fmt
, ap
);
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. */
352 tracing (const char fmt
[], ...)
356 vfprintf (stderr
, fmt
, ap
);
360 #define assert_not_reached() \
363 fputs(WHERE "You should never get here. Aborting execution.\n", \
370 #if DIE_IF_BADLY_BROKEN
371 #define BADLY_BROKEN fatalMsg
373 #define BADLY_BROKEN criticalMsg
374 /* So, the user may still attempt to recover, even though we do not advise
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) \
396 if ( DELETE_LOCAL_REFS ) \
398 (*env)->DeleteLocalRef (env, ref); \
404 /* Cached info for Exception-wrapping */
406 static jclass runtimeException_class
; /* java.lang.RuntimeException */
407 static 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. */
414 throw (JNIEnv
* env
, jthrowable cause
, const char *message
,
415 gboolean isBroken
, const char *file
, int line
)
418 gboolean describedException
= FALSE
; /* Did we already describe the
419 exception to stderr or the
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;
428 if (EXPLAIN_TROUBLE
|| (isBroken
&& EXPLAIN_BROKEN
))
430 criticalMsg ("%s:%d: AWT JNI failure%s: %s\n", file
, line
,
431 isBroken
? " (BROKEN)" : "", message
);
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
))
447 ("Relaunching an exception with Throw failed.");
453 DELETE_LOCAL_REF (env
, currentException
);
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
);
476 /* Create the RuntimeException wrapper object and throw it. It is OK for
478 wrapper
= (jthrowable
) (*env
)->NewObject
479 (env
, runtimeException_class
, runtimeException_ctor
, jmessage
, cause
);
480 DELETE_LOCAL_REF (env
, jmessage
);
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.
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");
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. */
512 ("GNU Classpath: Failure of JNI Throw to report an Exception");
516 DELETE_LOCAL_REF (env
, wrapper
);
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.) */
527 rethrow (JNIEnv
* env
, jthrowable cause
, const char *message
,
528 gboolean isBroken
, const char *file
, int line
)
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.
544 maybe_rethrow (JNIEnv
* env
, const char *message
, gboolean isBroken
,
545 const char *file
, int line
)
547 jthrowable cause
= (*env
)->ExceptionOccurred (env
);
550 /* rethrow if an exception happened */
553 ret
= rethrow (env
, cause
, message
, isBroken
, file
, line
);
554 DELETE_LOCAL_REF (env
, cause
);
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, \
579 #define BROKEN(_env, _message) \
580 rethrow (_env, (*env)->ExceptionOccurred (env), _message, TRUE, \
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
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
625 #define HIDE_OLD_TROUBLE(env) \
626 assert ( NULL == (*env)->ExceptionOccurred (env) )
628 #define SHOW_OLD_TROUBLE() \
629 assert ( NULL == (*env)->ExceptionOccurred (env) )
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) ) \
640 if ((*env)->Throw (env, savedTrouble)) \
641 BADLY_BROKEN ("ReThrowing the savedTrouble failed"); \
643 DELETE_LOCAL_REF (env, savedTrouble); \
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.
660 setup_exception_cache (JNIEnv
* env
)
662 static int exception_cache_initialized
= 0; /* -1 for trouble, 1 for proper
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");
672 BADLY_BROKEN1 ("Broken Class library or VM?"
673 " Couldn't find java/lang/RuntimeException");
674 return exception_cache_initialized
= -1;
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
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. */
776 setup_cache (JNIEnv
* env
)
779 static int initialized
= 0; /* 1 means initialized, 0 means uninitialized,
780 -1 means mis-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
));
794 assert ( ! (*env
)->ExceptionOccurred (env
));
796 /* java.lang.Object and its methods */
797 lcl_class
= (*env
)->FindClass (env
, "java/lang/Object");
800 BROKEN (env
, "cannot find java.lang.Object");
801 return initialized
= -1;
805 obj_class
= (jclass
) (*env
)->NewGlobalRef (env
, lcl_class
);
806 DELETE_LOCAL_REF (env
, lcl_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");
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;
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");
854 BROKEN (env
, "cannot find gnu.java.awt.peer.gtk.GThreadMutex");
855 return initialized
= -1;
858 mutex_class
= (jclass
) (*env
)->NewGlobalRef (env
, lcl_class
);
859 DELETE_LOCAL_REF (env
, lcl_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");
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");
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;
897 thread_class
= (jclass
) (*env
)->NewGlobalRef (env
, lcl_class
);
898 DELETE_LOCAL_REF (env
, lcl_class
);
901 BROKEN (env
, "Cannot get a global reference to java.lang.Thread");
902 return initialized
= -1;
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;
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;
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");
956 BROKEN (env
, "cannot find class java.lang.ThreadLocal");
957 return initialized
= -1;
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
,
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;
994 lcl_class
= (*env
)->FindClass (env
, "java/lang/Long");
997 BROKEN (env
, "cannot find class java.lang.Long");
998 return initialized
= -1;
1002 long_class
= (jclass
) (*env
)->NewGlobalRef (env
, lcl_class
);
1003 DELETE_LOCAL_REF (env
, lcl_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");
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 */
1028 (*env
)->FindClass (env
,
1029 "gnu/java/awt/peer/gtk/GThreadNativeMethodRunner");
1033 "cannot find gnu.java.awt.peer.gtk.GThreadNativeMethodRunner");
1034 return initialized
= -1;
1038 runner_class
= (jclass
) (*env
)->NewGlobalRef (env
, lcl_class
);
1039 DELETE_LOCAL_REF (env
, lcl_class
);
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
)
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
)
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
)
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
)
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");
1100 BROKEN (env
, "cannot find class java.lang.InterruptedException");
1101 return initialized
= -1;
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
));
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?).
1138 allocatePlainObject (JNIEnv
* env
)
1140 jobject lcl_obj
, global_obj
;
1142 lcl_obj
= (*env
)->NewObject (env
, obj_class
, obj_ctor
);
1145 BROKEN (env
, "cannot allocate object");
1149 global_obj
= (*env
)->NewGlobalRef (env
, lcl_obj
);
1150 DELETE_LOCAL_REF (env
, lcl_obj
);
1153 NEW_BROKEN (env
, "cannot make global ref for a new plain Java object");
1154 /* Deliberate fall-through */
1160 /* Frees any Java object given a global ref (isn't C fun?) */
1162 freeObject (JNIEnv
* env
, jobject 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()
1183 allocateMutexObject (JNIEnv
* env
)
1185 jobject lcl_obj
, global_obj
;
1187 lcl_obj
= (*env
)->NewObject (env
, mutex_class
, mutex_ctor
);
1190 BROKEN (env
, "cannot allocate a GThreadMutex");
1194 global_obj
= (*env
)->NewGlobalRef (env
, lcl_obj
);
1195 DELETE_LOCAL_REF (env
, lcl_obj
);
1198 NEW_BROKEN (env
, "cannot make global ref");
1199 /* Deliberate fallthrough */
1206 /************************************************************************/
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. */
1216 enterMonitor (JNIEnv
* env
, jobject monitorObj
, const char monName
[])
1219 tracing (" <MonitorEnter(%s)>", monName
);
1220 assert (monitorObj
);
1221 if ((*env
)->MonitorEnter (env
, monitorObj
) < 0)
1223 BROKEN (env
, "cannot enter monitor");
1230 /* Unlock a Java object */
1231 #define EXIT_MONITOR(env, m) \
1232 exitMonitor(env, m, G_STRINGIFY(m))
1235 exitMonitor (JNIEnv
* env
, jobject mutexObj
, const char monName
[])
1238 tracing (" <MonitorExit(%s)>", monName
);
1240 if ((*env
)->MonitorExit (env
, mutexObj
) < 0)
1242 BROKEN (env
, "cannot exit monitor ");
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.
1259 getThreadFromThreadID (JNIEnv
* env
, gpointer gThreadID
)
1261 jint threadNum
= GPOINTER_TO_INT(gThreadID
);
1266 NEW_BROKEN (env
, "getThreadFromThreadID asked to look up"
1267 " a negative thread index");
1271 thread
= (*env
)->CallStaticObjectMethod
1272 (env
, runner_class
, runner_threadIDToThread_mth
, threadNum
);
1274 if (MAYBE_BROKEN (env
, "cannot get Thread for threadID "))
1280 /** Return the unique threadID of THREAD.
1282 Error handling: Return (gpointer) -1 on all failures,
1283 and propagate an exception.
1286 getThreadIDFromThread (JNIEnv
* env
, jobject thread
)
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 "))
1305 SHOW_OLD_TROUBLE ();
1308 return GINT_TO_POINTER(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
1337 Guaranteed to leave all fields of the cache initialized, even if only to
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
);
1359 /* Clean out the mutexObj_cache, even if it was never populated. */
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. */
1372 mutexObj_lock (JNIEnv
* env
, jobject mutexObj
, struct mutexObj_cache
*mcache
)
1374 jint potentialLockers
;
1376 if (ENTER_MONITOR (env
, mcache
->lockForPotentialLockersObj
))
1381 (*env
)->GetIntField (env
, mutexObj
, mutex_potentialLockers_fld
);
1382 /* GetIntField() never fails. */
1387 (env
, mutexObj
, mutex_potentialLockers_fld
, potentialLockers
);
1389 if (EXIT_MONITOR (env
, mcache
->lockForPotentialLockersObj
))
1392 if (ENTER_MONITOR (env
, mcache
->lockObj
))
1395 SHOW_OLD_TROUBLE ();
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
1404 Returns -1 on error, 0 on success. */
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
1414 /* This is guaranteed not to block. */
1415 if (EXIT_MONITOR (env
, mcache
->lockObj
) < 0)
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)
1423 potentialLockers
= (*env
)->GetIntField
1424 (env
, mutexObj
, mutex_potentialLockers_fld
);
1425 /* GetIntField never fails */
1427 assert (potentialLockers
>= 1);
1431 (env
, mutexObj
, mutex_potentialLockers_fld
, potentialLockers
);
1432 /* Never fails, so the JNI book says. */
1435 if (EXIT_MONITOR (env
, mcache
->lockForPotentialLockersObj
) < 0)
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. */
1449 mutex_new_jni_impl (void)
1455 if (TRACE_API_CALLS
)
1456 tracing ("mutex_new_jni_impl()");
1459 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
1461 if (setup_cache (env
) < 0)
1467 mutexObj
= allocateMutexObject (env
);
1470 if (TRACE_API_CALLS
)
1471 tracing (" ==> %p \n", mutexObj
);
1473 return (GMutex
*) mutexObj
;
1479 mutex_lock_jni_impl (GMutex
* mutex
)
1481 struct mutexObj_cache mcache
;
1482 jobject mutexObj
= (jobject
) mutex
;
1486 if (TRACE_API_CALLS
)
1487 tracing ("mutex_lock_jni_impl( mutexObj = %p )", mutexObj
);
1491 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
1493 if (setup_cache (env
) < 0)
1496 HIDE_OLD_TROUBLE (env
);
1498 if (populate_mutexObj_cache (env
, mutexObj
, &mcache
) < 0)
1501 mutexObj_lock (env
, mutexObj
, &mcache
);
1502 /* No need to error check; we've already reported it in any case. */
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.
1514 mutex_trylock_jni_impl (GMutex
* gmutex
)
1516 jobject mutexObj
= (jobject
) gmutex
;
1517 jint potentialLockers
;
1518 gboolean ret
= FALSE
;
1521 struct mutexObj_cache mcache
;
1523 if (TRACE_API_CALLS
)
1524 tracing ("mutex_trylock_jni_impl(mutexObj=%p)", mutexObj
);
1529 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
1530 if (setup_cache (env
) < 0)
1532 HIDE_OLD_TROUBLE (env
);
1534 if (populate_mutexObj_cache (env
, mutexObj
, &mcache
) < 0)
1537 if (ENTER_MONITOR (env
, mcache
.lockForPotentialLockersObj
))
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. */
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. */
1565 /* We have the monitor. Record that fact. */
1566 potentialLockers
= 1;
1568 (env
, mutexObj
, mutex_potentialLockers_fld
, potentialLockers
);
1569 /* Set*Field() never fails */
1571 ret
= TRUE
; /* We have the lock. */
1574 if (EXIT_MONITOR (env
, mcache
.lockForPotentialLockersObj
))
1575 goto done
; /* If we fail at this point, still keep the
1578 SHOW_OLD_TROUBLE ();
1580 clean_mutexObj_cache (env
, &mcache
);
1581 if (TRACE_API_CALLS
)
1582 tracing (" ==> %s\n", ret
? "TRUE" : "FALSE");
1587 /* Unlock a mutex. */
1589 mutex_unlock_jni_impl (GMutex
* gmutex
)
1591 jobject mutexObj
= (jobject
) gmutex
;
1592 struct mutexObj_cache mcache
;
1596 if (TRACE_API_CALLS
)
1597 tracing ("mutex_unlock_jni_impl(mutexObj=%p)", mutexObj
);
1600 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
1601 if (setup_cache (env
) < 0)
1603 HIDE_OLD_TROUBLE (env
);
1607 if ( populate_mutexObj_cache (env
, mutexObj
, &mcache
) < 0)
1610 (void) mutexObj_unlock (env
, mutexObj
, &mcache
);
1612 SHOW_OLD_TROUBLE ();
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. */
1625 mutex_free_jni_impl (GMutex
* mutex
)
1627 jobject mutexObj
= (jobject
) mutex
;
1632 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_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. */
1652 cond_new_jni_impl (void)
1658 if (TRACE_API_CALLS
)
1659 tracing ("mutex_free_jni_impl()");
1662 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_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
1676 cond_signal_jni_impl (GCond
* gcond
)
1680 jobject condObj
= (jobject
) gcond
;
1682 if (TRACE_API_CALLS
)
1683 tracing ("cond_signal_jni_impl(condObj = %p)", condObj
);
1686 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
1687 if (setup_cache (env
) < 0)
1689 HIDE_OLD_TROUBLE (env
);
1693 /* Must have locked an object to call notify */
1694 if (ENTER_MONITOR (env
, condObj
))
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.");
1705 EXIT_MONITOR (env
, condObj
);
1707 SHOW_OLD_TROUBLE ();
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.
1718 cond_broadcast_jni_impl (GCond
* gcond
)
1720 jobject condObj
= (jobject
) gcond
;
1724 if (TRACE_API_CALLS
)
1725 tracing ("cond_broadcast_jni_impl(condObj=%p)", condObj
);
1728 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
1729 if (setup_cache (env
) < 0)
1731 HIDE_OLD_TROUBLE (env
);
1734 /* Must have locked an object to call notifyAll */
1735 if (ENTER_MONITOR (env
, condObj
))
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
);
1745 EXIT_MONITOR (env
, condObj
);
1747 SHOW_OLD_TROUBLE ();
1750 if (TRACE_API_CALLS
)
1751 tracing (" ==> VOID\n");
1755 /* Wait on a condition variable. For us, this simply means calling
1758 * Throws a Java exception on trouble; may leave the mutexes set arbitrarily.
1759 * XXX TODO: Further improve error recovery.
1762 cond_wait_jni_impl (GCond
* gcond
, GMutex
* gmutex
)
1764 struct mutexObj_cache cache
;
1765 jobject condObj
= (jobject
) gcond
;
1766 jobject mutexObj
= (jobject
) gmutex
;
1770 if (TRACE_API_CALLS
)
1771 tracing ("cond_wait_jni_impl(condObj=%p, mutexObj=%p)",
1775 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
1776 if (setup_cache (env
) < 0)
1778 HIDE_OLD_TROUBLE (env
);
1782 /* Must have locked a Java object to call wait on it */
1783 if (ENTER_MONITOR (env
, condObj
) < 0)
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
))
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 */
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
))
1803 EXIT_MONITOR (env
, condObj
);
1805 SHOW_OLD_TROUBLE ();
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
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.
1831 cond_timed_wait_jni_impl (GCond
* gcond
, GMutex
* gmutex
, GTimeVal
* end_time
)
1835 jlong time_millisec
;
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
);
1854 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
1855 if (setup_cache (env
) < 0)
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)
1866 if (mutexObj_unlock (env
, mutexObj
, &cache
) < 0)
1868 if (EXIT_MONITOR (env
, condObj
) < 0)
1870 ("Unable to unlock an existing lock on a condition; your proram may deadlock");
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
);
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. */
1896 interrupted
= FALSE
; /* Trouble, but not because of
1897 InterruptedException. Assume the condition
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
);
1913 if (EXIT_MONITOR (env
, condObj
) && !cause
)
1915 cause
= (*env
)->ExceptionOccurred (env
);
1919 if (cause
) /* Raise the first cause. */
1921 BROKEN_CAUSE (env
, cause
, "error in timed wait or during its cleanup");
1925 SHOW_OLD_TROUBLE ();
1928 if (TRACE_API_CALLS
)
1929 tracing (" ==> condRaised = %s\n", condRaised
? "TRUE" : "FALSE");
1934 /* Free a condition variable. (isn't C fun?). Can not fail. */
1936 cond_free_jni_impl (GCond
* cond
)
1938 jobject condObj
= (jobject
) cond
;
1942 if (TRACE_API_CALLS
)
1943 tracing ("cond_free_jni_impl(condObj = %p)", condObj
);
1945 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_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
1962 * We will throw a Java exception and return NULL in case of failure.
1965 private_new_jni_impl (GDestroyNotify notify
__attribute__ ((unused
)))
1971 GPrivate
*gkey
= NULL
; /* Error return code */
1973 if (TRACE_API_CALLS
)
1974 tracing ("private_new_jni_impl()");
1977 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
1978 if (setup_cache (env
) < 0)
1980 HIDE_OLD_TROUBLE (env
);
1982 lcl_key
= (*env
)->NewObject (env
, threadlocal_class
, threadlocal_ctor
);
1985 BROKEN (env
, "cannot allocate a ThreadLocal");
1989 global_key
= ((*env
)->NewGlobalRef (env
, lcl_key
));
1990 DELETE_LOCAL_REF (env
, lcl_key
);
1993 NEW_BROKEN (env
, "cannot create a GlobalRef to a new ThreadLocal");
1997 gkey
= (GPrivate
*) global_key
;
1998 SHOW_OLD_TROUBLE ();
2001 if (TRACE_API_CALLS
)
2002 tracing (" ==> %p\n", (void *) 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.)
2012 private_get_jni_impl (GPrivate
* gkey
)
2016 jobject val_wrapper
;
2017 jobject keyObj
= (jobject
) gkey
;
2018 gpointer thread_specific_data
= NULL
; /* Init to the error-return value */
2022 if (TRACE_API_CALLS
)
2023 tracing ("private_get_jni_impl(keyObj=%p)", keyObj
);
2026 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
2027 if (setup_cache (env
) < 0)
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"))
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
2042 thread_specific_data
= NULL
;
2046 val
= (*env
)->CallLongMethod (env
, val_wrapper
, long_longValue_mth
);
2048 if (MAYBE_BROKEN (env
, "cannot get thread local value"))
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
2055 SHOW_OLD_TROUBLE ();
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.
2069 private_set_jni_impl (GPrivate
* gkey
, gpointer thread_specific_data
)
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
);
2082 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
2083 if (setup_cache (env
) < 0)
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
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");
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"))
2108 SHOW_OLD_TROUBLE ();
2110 if (TRACE_API_CALLS
)
2111 tracing (" ==> VOID\n");
2115 /** Create an object of type gnu.java.awt.peer.gtk.GThreadNativeMethodRunner.
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.
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
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
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
2144 thread_create_jni_impl (GThreadFunc func
,
2146 gulong stack_size
__attribute__((unused
)),
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. */
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
)))
2162 jboolean jjoinable
= joinable
;
2163 jobject newThreadObj
;
2164 gpointer threadID
; /* to be filled in */
2166 if (TRACE_API_CALLS
)
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
);
2176 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_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
;
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. */
2190 (*env
)->NewObject (env
, runner_class
, runner_ctor
,
2191 (jlong
) (intptr_t) func
, (jlong
) (intptr_t) data
,
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. */
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
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
2223 So, we don't use g_set_error() here to perform any error reporting.
2228 threadID
= getThreadIDFromThread (env
, newThreadObj
);
2230 *(gpointer
*) threadIDp
= threadID
;
2231 SHOW_OLD_TROUBLE ();
2234 if (TRACE_API_CALLS
)
2235 tracing (" ==> (threadID = %p) \n", threadID
);
2239 /* Wraps a call to g_thread_yield. */
2241 thread_yield_jni_impl (void)
2246 if (TRACE_API_CALLS
)
2247 tracing ("thread_yield_jni_impl()");
2250 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
2251 if (setup_cache (env
) < 0)
2253 HIDE_OLD_TROUBLE (env
);
2255 (*env
)->CallStaticVoidMethod (env
, thread_class
, thread_yield_mth
);
2256 if (MAYBE_BROKEN (env
, "Thread.yield() failed"))
2259 SHOW_OLD_TROUBLE ();
2262 if (TRACE_API_CALLS
)
2263 tracing (" ==> VOID\n");
2268 thread_join_jni_impl (gpointer threadID
)
2272 jobject threadObj
= NULL
;
2274 if ( TRACE_API_CALLS
)
2275 tracing ("thread_join_jni_impl(threadID=%p) ", threadID
);
2278 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
2279 if (setup_cache (env
) < 0)
2281 HIDE_OLD_TROUBLE (env
);
2283 threadObj
= getThreadFromThreadID (env
, threadID
);
2284 if ( ! threadObj
) /* Already reported with BROKEN */
2287 (*env
)->CallVoidMethod (env
, threadObj
, thread_join_mth
);
2288 if (MAYBE_BROKEN (env
, "Thread.join() failed"))
2292 (*env
)->CallStaticVoidMethod
2293 (env
, runner_class
, runner_deRegisterJoinable_mth
, threadObj
);
2294 if (MAYBE_BROKEN (env
, "Thread.deRegisterJoinableThread() failed"))
2297 SHOW_OLD_TROUBLE ();
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. */
2316 thread_exit_jni_impl (void)
2320 jobject this_thread
;
2322 if (TRACE_API_CALLS
)
2323 tracing ("thread_exit_jni_impl() ");
2326 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
2327 if (setup_cache (env
) < 0)
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");
2341 (*env
)->CallVoidMethod (env
, this_thread
, thread_stop_mth
);
2342 if (MAYBE_BROKEN (env
, "cannot call Thread.stop() on current thread"))
2345 SHOW_OLD_TROUBLE ();
2348 if (TRACE_API_CALLS
)
2349 tracing (" ==> VOID \n");
2353 /* Translate a GThreadPriority to a Java priority level. */
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
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
;
2376 case G_THREAD_PRIORITY_LOW
:
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
:
2388 case G_THREAD_PRIORITY_HIGH
:
2389 return (normJPri
+ maxJPri
) / 2;
2392 case G_THREAD_PRIORITY_URGENT
:
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.
2404 thread_set_priority_jni_impl (gpointer gThreadID
, GThreadPriority gpriority
)
2406 jobject threadObj
= NULL
;
2410 if (TRACE_API_CALLS
)
2411 tracing ("thread_set_priority_jni_impl(gThreadID=%p, gpriority = %u) ",
2412 gThreadID
, gpriority
);
2415 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
2417 if (setup_cache (env
) < 0)
2420 HIDE_OLD_TROUBLE (env
);
2423 threadObj
= getThreadFromThreadID (env
, gThreadID
);
2424 if ( ! threadObj
) /* Reported with BROKEN already. */
2427 if (threadObj_set_priority (env
, threadObj
, gpriority
))
2430 SHOW_OLD_TROUBLE ();
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. */
2446 threadObj_set_priority (JNIEnv
* env
, jobject threadObj
,
2447 GThreadPriority gpriority
)
2449 jint javaPriority
= javaPriorityLevel (gpriority
);
2450 (*env
)->CallVoidMethod (env
, threadObj
, thread_setPriority_mth
,
2452 return MAYBE_BROKEN (env
, "Thread.setPriority() failed");
2456 /** Return the result of Thread.currentThread(), a static method. */
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
)
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
);
2472 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_the_vm
, e
.void_env
, JNI_VERSION_1_1
);
2474 if (setup_cache (env
) < 0)
2477 HIDE_OLD_TROUBLE (env
);
2479 this_thread
= (*env
)->
2480 CallStaticObjectMethod (env
, thread_class
, thread_current_mth
);
2483 BROKEN (env
, "cannot get current thread");
2488 my_threadID
= getThreadIDFromThread (env
, this_thread
);
2489 SHOW_OLD_TROUBLE ();
2492 if (TRACE_API_CALLS
)
2493 tracing (" ==> (my_threadID = %p) \n", my_threadID
);
2495 *(gpointer
*) my_thread_IDp
= my_threadID
;
2500 thread_equal_jni_impl (gpointer thread1
, gpointer thread2
)
2505 gpointer threadID1
= *(gpointer
*) thread1
;
2506 gpointer threadID2
= *(gpointer
*) thread2
;
2508 jobject thread1_obj
= NULL
;
2509 jobject thread2_obj
= NULL
;
2512 if (TRACE_API_CALLS
)
2513 tracing ("thread_equal_jni_impl(threadID1=%p, threadID2=%p)",
2514 threadID1
, threadID2
);
2517 (*cp_gtk_the_vm
)->GetEnv (cp_gtk_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. */
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"))
2538 SHOW_OLD_TROUBLE ();
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");
2554 /************************************************************************/
2555 /* GLIB interface */
2556 /************************************************************************/
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 */
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"
2591 "jboolean" "jclass" "jfieldID" "jint" "jlong" "jmethodID" "jobject" "jstring" "jthrowable" ) */