Contents
TCL Thread
- With Scilab 5.0 alpha 1 has been released a new communication process between Tcl and Scilab.
Tcl Global Interpreter
- Starting Scilab will create a global Tcl Interpreter (same process as in Scilab 4.1.2).
- This interpreter is used to manage direct access to Tcl functions from Scilab:
TCL_CreateSlave
- This function will create a slave interpreter linked to the global Scilab Tcl interpreter.
TCL_DeleteInterp
- This function will delete a slave interpreter.
- One can not delete the global scilab interpreter. It will be destroyed when Scilab exits.
TCL_DoOneEvent
This function is a direct mapping to the Tcl_DoOneEvent function in the Tcl Library. Function Tcl_DoOneEvent waits for events and invokes event handlers. More precisely, what is invoked is Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT) - See details about what this means exactly
TCL_EvalFile
- This function gives a file to evaluate to a dedicated interpreter.
- If none is specified, the Scilab global one is used.
TCL_EvalStr
- This function gives a command to evaluate to a dedicated interpreter.
- If none is specified, the Scilab global one is used.
TCL_ExistArray
- This function checks if the given variable exists and is an array in the given interpreter.
- If none is specified, the Scilab global one is used.
TCL_ExistInterp
- This function checks if the given slave exists.
TCL_ExistVar
- This function checks if the given variable exists in the given interpreter.
- If none is specified, the Scilab global one is used.
TCL_GetVar
- This function returns a variable stored in the given interpreter.
- If none is specified, the Scilab global one is used.
TCL_SetVar
- This function stores a variable in the given interpreter.
- If none is specified, the Scilab global one is used.
TCL_GetVersion
- This function returns the current Tcl/Tk version linked to Scilab.
TCL_UnsetVar
- This function deletes a variable in the given interpreter.
- If none is specified, the Scilab global one is used.
TCL_UpVar
- Makes a link from a Tcl source variable to a Tcl destination variable.
TCL_gcf : DEPRECATED
- This function returns the current figure number.
- In Scilab 4.X graphical windows were managed with Tcl/Tk.
- That is no longer the case.
For compatibility this function is kept and uses Scilab gcf
TCL_scf : DEPRECATED
- This function sets the current figure number.
- In Scilab 4.X graphical windows were managed with Tcl/Tk.
- That is no longer the case.
For compatibility this function is kept and uses Scilab scf
How it works in Scilab 5.0
Global issue
- With Scilab 5.0 we break the endless Scilab main loop and replace it by threaded process (especially with the Java GUI).
In Scilab 4.X the main endless loop was used to periodically ask the global Tcl interp to do an update or DoOneEvent. This action was keeping Tk GUI alive.
We have chosen to have a dedicated thread to emulate this periodical update process.
- This raises the issue, we have to make the commands interpreted in the same thread where the global interpreter was created. So we added methods and access control to this interpreter.
For synchronization process we had to lock the global Tcl interp, in order that no concurrent access can happen. This leads to the fact that re-entering process such as TCL_EvalStr ... ScilabEval ... TCL_EvalStr will not be allowed.
Tcl dedicated thread
Initialization
- When launching Scilab, we create a Tcl dedicated thread in which the global Scilab Tcl Interpreter is running.
This process is done in SCI/modules/tclsci/src/c/InitTclTk.c
We call OpenTCLsci
this launches a dedicated thread DaemonOpenTCLsci
and waits for a signal InterpReady telling that the global interpreter is now ready so that Scilab init can go on.
DaemonOpenTCLsci
- This creates the global Scilab Tcl interpreter and performs all the initialization.
Once the initialization is done it raises InterpReady
Then it starts startTclLoop
startTclLoop
First it creates a periodic signal thread: sleepAndSignal
- Then it starts to loop while Tcl is running (it means, while Scilab is running)
- If there are commands to provide to the global interpreter or to one slave, they are provided to the interpreter for evaluation
If there is none, the interpreter is simply asked to update This makes Tcl/Tk GUIs "alive"
Then it waits for a signal wakeUp before restarting the loop.
sleepAndSignal
- This is the "awaking" loop.
- While Tcl is running (it means, while Scilab is running), it sleeps for some time
Then raises wakeUp signal to awake the TclLoop if it was waiting.
- Loop.
sendTclFileToSlave / sendTclCommandToSlave
- Those functions are used to send commands or a file to be evaluated by a Tcl Interpreter (slave or global).
- Now that we have a dedicated thread for the Tcl/Tk, we had to make it communicate with the Scilab thread.
- These functions lock the global Tcl interpreter (in order to prevent concurrent access) and provide it with something to run.
getTclCommandReturn / getTclCommandResult
- These functions are used to retrieve the results of the Tcl evaluation. The return value and any message that may have been returned by Tcl execution are provided to the caller.
Details on Threading and Communication Process
Sleep And Signal Loop
This loop will ask for a periodical update in the main TCL Interpreter.
Main Tcl Loop
- This loop make the TCL gui alive and execute the command given in the dedicated TCL Thread.
The update process is waked up by the Sleep And Signal Loop.
How to ask for a File evaluation (TCL_EvalFile)
- This functions can be call from any thread and ask the evaluation in the TCL dedicated thread.
If slave is null the evaluation is done within the main TCL Interpreter.
How to ask for a Command evaluation (TCL_EvalStr)
- This functions can be call from any thread and ask the evaluation in the TCL dedicated thread.
If slave is null the evaluation is done within the main TCL Interpreter.
There is a shortcut in order we can call a TCL_EvalStr within a TCL_EvalFile. It is safe because the TCL interpreter
has already been locked.
Known Drawbacks
Re-entering call issue
Reentering process like TCL_EvalStr (... ScilabEval( ... TCL_EvalStr(...))) will enter a deadlock process:
The first TCL_Evalstr will lock the global interp and give it the command to evaluate.
The call to ScilabEval will ask for the global interp and try to lock it. But it has already been locked by the first call, so it will wait until the first TCL_Evalstr is over.
ScilabEval is waiting for the end of TCL_Evalstr to get access to the global interpreter.
TCL_Evalstr can only finish (and then unlock the interpreter) after ScilabEval has returned.
SOLUTION: Re-entering call issue
Encapsulation now fully works embedding ScilabEval and TCL_EvalStr
Dead Lock accessing TCL Interpreter
A direct acces to the interpreter (done by the TCL Library) goes through our locking process : getTclInterp // releaseTclInterp.
For instance : TCL_EvalStr("ScilabEval ""TCL_SetVar(\""myVar\"", \""myValue\"")"" ""sync"" ""seq"" ")
TCL_EvalStr locks the Global Interpreter.
Then the ScilabEval is requested as synchronous (sync) and un breackable (seq).
This mean TCl_EvalStr will return after ScilabEval has returned.
TCL_SetVar do getTclInterp to acquire the lock handled by TCL_EvalStr. So it wait until it is released... (that will never happened).
SOLUTION: Dead Lock accessing TCL Interpreter
TCL_EvalStr("ScilabEval ""TCL_SetVar(\""myVar\"", \""myValue\"")"" ""seq"" ") Remove the sync option so that the command is queued and executed later. But you have no more control on when it will be done.
- Try to execute functions where the variable are living : (ex: Some message box)
- in Scilab :
TCL_EvalStr("ScilabEval ""messagebox(getdebuginfo(), \""Title\"", \""info\"")"" ""sync"" ""seq"" ")
instead of setting getdebuginfo() returns values in Scilab and tranfer it into TCL Interpreter through a TCL_SetVar.
- in TCL :
tk_messageBox -title "What my computer looks like" -message [concat "here it is :" [exec uname -m]] -icon error
instead of setting exec uname -m in a TCL variable and then order a TCL_GetVar in Scilab.
- in Scilab :