/* * 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); }