/*
* javaNotifier.c --
*
* This file contains the native methods for the Notifier class.
*
* Copyright (c) 1998 by Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: javaNotifier.c,v 1.7 2002/12/30 05:53:29 mdejong Exp $
*/
#include "java.h"
#include "javaNative.h"
typedef struct ThreadSpecificData {
jobject notifierObj;
int eventQueued;
int doOneEventCount;
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
/* Define this here so that we do not need to include tclInt.h */
#define TCL_TSD_INIT(keyPtr) (ThreadSpecificData *)Tcl_GetThreadData((keyPtr), sizeof(ThreadSpecificData))
/*
* Declarations for functions used only in this file.
*/
static int JavaEventProc(Tcl_Event *evPtr, int flags);
static void NotifierCheck(ClientData data, int flags);
static void NotifierSetup(ClientData data, int flags);
/*
*----------------------------------------------------------------------
*
* Java_tcl_lang_Notifier_init --
*
* Initialize the Java Notifier event source.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
jlong JNICALL
Java_tcl_lang_Notifier_init(
JNIEnv *env, /* Java environment. */
jobject notifierObj) /* Handle to Notifier object. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
jlong tid;
tsdPtr->notifierObj = (*env)->NewGlobalRef(env, notifierObj);
tsdPtr->eventQueued = 0;
tsdPtr->doOneEventCount = 0;
/* If we segfault near here under Windows, try removing tclblend.dll
* from the current directory. Tcl Blend has problems loading
* dlls from a remote directory if there is a dll with the
* same name in the local directory.
*/
Tcl_CreateEventSource(NotifierSetup, NotifierCheck, NULL);
tid = 0;
*(Tcl_ThreadId *)&tid = Tcl_GetCurrentThread();
return tid;
}
/*
*----------------------------------------------------------------------
*
* Java_tcl_lang_Notifier_dispose --
*
* Clean up the Java Notifier event source.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void JNICALL
Java_tcl_lang_Notifier_dispose(
JNIEnv *env, /* Java environment. */
jobject notifierObj) /* Handle to Notifier object. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_DeleteEventSource(NotifierSetup, NotifierCheck, NULL);
(*env)->DeleteGlobalRef(env, tsdPtr->notifierObj);
tsdPtr->notifierObj = NULL;
}
/*
*----------------------------------------------------------------------
*
* Java_tcl_lang_Notifier_doOneEvent --
*
* Process one event from the event queue.
*
* Results:
* Returns the result of Tcl_DoOneEvent().
*
* Side effects:
* May invoke arbitrary code.
*
*----------------------------------------------------------------------
*/
jint JNICALL
Java_tcl_lang_Notifier_doOneEvent(
JNIEnv *env, /* Java environment. */
jobject notifierObj, /* Handle to Notifier object. */
jint flags) /* Miscellaneous flag values: may be any
* combination of TCL.DONT_WAIT,
* TCL.WINDOW_EVENTS, TCL.FILE_EVENTS,
* TCL.TIMER_EVENTS, TCL.IDLE_EVENTS,
* or others defined by event sources. */
{
int result;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->doOneEventCount++;
result = Tcl_DoOneEvent(flags);
tsdPtr->doOneEventCount--;
return result;
}
/*
*----------------------------------------------------------------------
*
* Java_tcl_lang_Notifier_alertNotifier --
*
* Wake up the Tcl Notifier so it can check the event sources.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void JNICALL
Java_tcl_lang_Notifier_alertNotifier(
JNIEnv *env, /* Java environment. */
jobject notifierObj, /* Handle to Notifier object. */
jlong tid) /* Tcl_ThreadId for the notifier thread */
{
Tcl_ThreadAlert(*(Tcl_ThreadId *)&tid);
}
/*
*----------------------------------------------------------------------
*
* NotifierSetup --
*
* This routine checks to see if there are any events on the
* Java Notifier queue.
*
* Results:
* None.
*
* Side effects:
* May set the block time to 0.
*
*----------------------------------------------------------------------
*/
static void
NotifierSetup(
ClientData data, /* Not used. */
int flags) /* Same as for Tcl_DoOneEvent. */
{
JNIEnv *env = JavaGetEnv();
JavaInfo* jcache = JavaGetCache();
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if ((*env)->CallBooleanMethod(env, tsdPtr->notifierObj, jcache->hasEvents)
== JNI_TRUE) {
Tcl_Time timeout = { 0, 0 };
Tcl_SetMaxBlockTime(&timeout);
}
}
/*
*----------------------------------------------------------------------
*
* NotifierCheck --
*
* This routine checks to see if there are any events on the
* Java Notifier queue.
*
* Results:
* None.
*
* Side effects:
* May queue a JavaEvent on the event queue.
*
*----------------------------------------------------------------------
*/
static void
NotifierCheck(
ClientData data, /* Not used. */
int flags) /* Same as for Tcl_DoOneEvent. */
{
Tcl_Event *ePtr;
JNIEnv *env = JavaGetEnv();
JavaInfo* jcache = JavaGetCache();
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
/*
* Only queue a new event if there isn't already one queued and
* there are events on the Java event queue.
*/
if (!tsdPtr->eventQueued &&
(*env)->CallBooleanMethod(env, tsdPtr->notifierObj,
jcache->hasEvents) == JNI_TRUE) {
ePtr = (Tcl_Event *) ckalloc(sizeof(Tcl_Event));
ePtr->proc = JavaEventProc;
Tcl_QueueEvent(ePtr, TCL_QUEUE_TAIL);
tsdPtr->eventQueued = 1;
}
}
/*
*----------------------------------------------------------------------
*
* JavaEventProc --
*
* This procedure is invoked when a JavaEvent is processed from
* the Tcl event queue.
*
* Results:
* None.
*
* Side effects:
* Invokes arbitrary Java code.
*
*----------------------------------------------------------------------
*/
static int
JavaEventProc(
Tcl_Event *evPtr, /* The event that is being processed. */
int flags) /* The flags passed to Tcl_ServiceEvent. */
{
JNIEnv *env = JavaGetEnv();
JavaInfo* jcache = JavaGetCache();
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
Tcl_Panic("JavaEventProc : unexpected pending exception");
}
/*
* Call Notifier.serviceEvent() to handle invoking the next event and
* signaling any threads that are waiting on the event.
*/
tsdPtr->eventQueued = 0;
(void) (*env)->CallIntMethod(env, tsdPtr->notifierObj,
jcache->serviceEvent, flags);
if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
Tcl_Panic("JavaEventProc : exception in Notifier.serviceEvent()");
}
return 1;
}
/*
*----------------------------------------------------------------------
*
* Java_tcl_lang_Notifier_finalizeThreadCheck --
*
* Checks to see if the Notifier for this thread has been
* released because the last interpreter in the thread was
* disposed of. If so, the cleanup Tcl's thread local storage.
*
* Class: tcl_lang_Notifier
* Method: finalizeThreadCheck
* Signature: ()V;
*
* Results:
* Releases thread specific data.
*
* Side effects:
* Thread may detach from JVM, or JVM may be destroyed.
*
*----------------------------------------------------------------------
*/
void JNICALL
Java_tcl_lang_Notifier_finalizeThreadCheck(
JNIEnv *env, /* Java environment. */
jclass notifierClass) /* Handle to Notifier class. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if ((tsdPtr->notifierObj == NULL) && JavaWasJavaThreadInit()) {
#ifdef TCLBLEND_DEBUG
fprintf(stderr, "TCLBLEND_DEBUG: Invoking Tcl_FinalizeThread\n");
#endif /* TCLBLEND_DEBUG */
Tcl_FinalizeThread();
#ifdef TCLBLEND_DEBUG
fprintf(stderr, "TCLBLEND_DEBUG: Done with Tcl_FinalizeThread\n");
#endif /* TCLBLEND_DEBUG */
} else {
#ifdef TCLBLEND_DEBUG
fprintf(stderr, "TCLBLEND_DEBUG: Tcl Thread data not finalized\n");
#endif /* TCLBLEND_DEBUG */
}
}
/*
*----------------------------------------------------------------------
*
* JavaNotifierInDoOneEvent --
*
* Returns true if the notifier for this thread is currently
* executing Tcl_DoOneEvent in the doOneEvent() native
* method.
*
* Results:
* 1 or 0.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
JavaNotifierInDoOneEvent()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return (tsdPtr->doOneEventCount > 0);
}