guithread.cpp

Go to the documentation of this file.
00001 #define TCL_THREADS
00002 // fies: Wenn nicht definiert, funktionieren die Mutexes etc. nicht
00003 #include <tk.h>
00004 #include <tcl.h>
00005 #include <cstdio>
00006 #include <malloc.h>
00007 #include <cmath>
00008 #include <cstring>
00009 #include <iostream>
00010 //#include <windows.h>
00011 //#undef min
00012 // #undef max
00013 // Grrr - stupid "windows.h" defines min and max as macro
00014 // it clashes with valarray::max
00015 #include "imgclass.hpp"
00016 #include "xgray_tcl.hpp"
00017 #include "guithread.hpp"
00018 
00019 using namespace std;
00020 
00021 extern "C" int Xgray_Init(Tcl_Interp *);
00022 
00023 
00024 TCL_DECLARE_MUTEX(threadMutex)
00025 
00026 struct ThreadEvent  {
00027     Tcl_Event event;            /* Must be first */
00028     char *script;               /* The script to execute. */
00029     Tcl_Interp *interp;
00030     
00031     struct ThreadEventResult *resultPtr;
00032                                 /* To communicate the result.  This is
00033                                  * NULL if we don't care about it. */
00034 };
00035 
00036 struct ThreadEventResult {
00037     Tcl_Condition done;         /* Signaled when the script completes */
00038     int code;                   /* Return value of Tcl_Eval */
00039     char *result;               /* Result from the script */
00040     char *errorInfo;            /* Copy of errorInfo variable */
00041     char *errorCode;            /* Copy of errorCode variable */
00042     Tcl_ThreadId srcThreadId;   /* Id of sending thread, in case it dies */
00043     Tcl_ThreadId dstThreadId;   /* Id of target thread, in case it dies */
00044     struct ThreadEvent *eventPtr;       /* Back pointer */
00045     struct ThreadEventResult *nextPtr;  /* List for cleanup */
00046     struct ThreadEventResult *prevPtr;
00047 
00048 };
00049 
00050 static void
00051 ThreadFreeProc(ClientData clientData)
00052 {
00053     if (clientData) {
00054         ckfree((char *) clientData);
00055     }
00056 }
00057 
00058 static int ThreadEventProc(
00059     Tcl_Event *evPtr,           /* Really ThreadEvent */
00060     int mask)
00061 {
00062     ThreadEvent *threadEventPtr = (ThreadEvent *)evPtr;
00063     ThreadEventResult *resultPtr = threadEventPtr->resultPtr;
00064     Tcl_Interp *interp = threadEventPtr->interp;
00065     int code;
00066     const char *result, *errorCode, *errorInfo;
00067 
00068     if (interp == NULL) {
00069         code = TCL_ERROR;
00070         result = "no target interp!";
00071         errorCode = "THREAD";
00072         errorInfo = "";
00073     } else {
00074         Tcl_Preserve((ClientData) interp);
00075         Tcl_ResetResult(interp);
00076         Tcl_CreateThreadExitHandler(ThreadFreeProc,
00077                 (ClientData) threadEventPtr->script);
00078         code = Tcl_GlobalEval(interp, threadEventPtr->script);
00079         Tcl_DeleteThreadExitHandler(ThreadFreeProc,
00080                 (ClientData) threadEventPtr->script);
00081         if (code != TCL_OK) {
00082             errorCode = Tcl_GetVar(interp, "errorCode", TCL_GLOBAL_ONLY);
00083             errorInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
00084         } else {
00085             errorCode = errorInfo = NULL;
00086         }
00087         result = Tcl_GetStringResult(interp);
00088     }
00089     ckfree(threadEventPtr->script);
00090     if (interp != NULL) {
00091         Tcl_Release((ClientData) interp);
00092     }
00093     return 1;
00094 }
00095 
00096 
00097 int tcl_thread_send(Tcl_ThreadId id, Tcl_Interp* interp, const char *script)
00098  {
00099     ThreadEvent *threadEventPtr;
00100     ThreadEventResult *resultPtr;
00101     int found, code;
00102     Tcl_ThreadId threadId = (Tcl_ThreadId) id;
00103 
00104     Tcl_MutexLock(&threadMutex);
00105     /* 
00106      * Create the event for its event queue.
00107      */
00108 
00109     threadEventPtr = (ThreadEvent *) ckalloc(sizeof(ThreadEvent));
00110     threadEventPtr->script = ckalloc(strlen(script) + 1);
00111     threadEventPtr->interp = interp;
00112     strcpy(threadEventPtr->script, script);
00113     resultPtr = threadEventPtr->resultPtr = NULL;
00114    
00115     /*
00116      * Queue the event and poke the other thread's notifier.
00117      */
00118 
00119     threadEventPtr->event.proc = ThreadEventProc;
00120     Tcl_ThreadQueueEvent(threadId, (Tcl_Event *)threadEventPtr, 
00121             TCL_QUEUE_TAIL);
00122     Tcl_ThreadAlert(threadId);
00123 
00124     
00125     Tcl_MutexUnlock(&threadMutex);
00126     return TCL_OK;
00127 }
00128 
00129 
00130 
00131 extern "C" {
00132  static int AppInit(Tcl_Interp *interp);
00133  static Tcl_ThreadCreateType slaveinterpreter (ClientData dummy);
00134 }
00135 
00136 
00137  
00138   static Tcl_ThreadId displaythreadId=0;
00139   static Tcl_Interp *interp=NULL;
00140   static int argc=0;
00141   static const char ** argv=NULL;
00142   static Tcl_Condition startup_condition=NULL;
00143   static volatile bool started=false;
00144   
00145 int AppInit(Tcl_Interp *interp_) {
00146         interp = interp_;
00147 
00148         Tcl_SetVar(interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
00149         if(Tcl_Init(interp) == TCL_ERROR) return TCL_ERROR;
00150         if(Tk_Init(interp) == TCL_ERROR) return TCL_ERROR;
00151         if (Xgray_Init(interp)==TCL_ERROR) return TCL_ERROR;
00152        
00153 
00154         cout<<"T2"<<endl<<flush;
00155         Tcl_MutexLock(&threadMutex);
00156         
00157         // Doof: Ich muss noch eine extra Variable setzen
00158         // ConditionWait kann auch so zurückkommen ???
00159         started=true;
00160         Tcl_ConditionNotify(&startup_condition);
00161         Tcl_MutexUnlock(&threadMutex);
00162         // Der Start gelang
00163         return TCL_OK;
00164 }
00165 
00166 Tcl_ThreadCreateType slaveinterpreter (ClientData dummy) {
00167     Tcl_Channel  outChannel;
00168     
00169     Tcl_Interp *interp = Tcl_CreateInterp();
00170     /*
00171      * Ensure that we are getting the matching version of Tcl.  This is
00172      * really only an issue when Tk is loaded dynamically.
00173      */
00174 
00175     if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) {
00176         abort();
00177     }
00178     
00179 
00180 #ifdef MAC_OSX_TK
00181     {
00182         TkMacOSXDefaultStartupScript();
00183     }
00184 #endif
00185     
00186     /*
00187      * Set the "tcl_interactive" variable.
00188      */
00189 
00190     Tcl_SetVar(interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
00191 
00192     /*
00193      * Invoke application-specific initialization.
00194      */
00195 
00196     if (AppInit(interp) != TCL_OK) {
00197         return 0;
00198     }
00199 
00200     /*
00201      * Invoke the script specified on the command line, if any.
00202      */
00203 
00204    
00205     outChannel = Tcl_GetStdChannel(TCL_STDOUT);
00206     if (outChannel) {
00207         Tcl_Flush(outChannel);
00208     }
00209     
00210     Tcl_ResetResult(interp);
00211 
00212     /*
00213      * Loop infinitely, waiting for commands to execute.  When there
00214      * are no windows left, Tk_MainLoop returns and we exit.
00215      */
00216 
00217     Tk_MainLoop();
00218     Tcl_DeleteInterp(interp);
00219     /*Tcl_Exit(0);*/
00220 
00221   return 0;
00222 } 
00223 
00224 
00225 Tclthread::Tclthread(int argc_, const char **argv_)
00226 {
00227   int result;
00228   argc=argc_;
00229   argv=argv_;
00230   
00231   
00232   Tcl_FindExecutable(argv[0]);
00233   Tcl_MutexLock(&threadMutex);
00234   result=Tcl_CreateThread(&displaythreadId, slaveinterpreter, (ClientData)0, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
00235 
00236   // hier sollte irgendein ConditionWait feststellen,
00237   // ob der Interpreter wirklich läuft
00238   int nr=0;
00239   while (!started) {
00240     Tcl_ConditionWait(&startup_condition, &threadMutex, NULL);
00241     nr++;
00242   }
00243   
00244   operator() (
00245 #include "inlinedisplay.c++"
00246  );
00247   // Startupskript ausführen
00248   Tcl_MutexUnlock(&threadMutex);
00249   cout<<"T1 "<<nr<<endl<<flush;
00250 }
00251 
00252 
00253 void Tclthread::operator () (const char *script) {
00254   tcl_thread_send(displaythreadId, interp, script);
00255   // fire and forget
00256 }  
00257 
00258 

Generated on Fri Jul 24 12:49:17 2009 for Xgrayimg Library by  doxygen 1.5.5