Next Previous Contents

4. Implementation details (version 0.1)

This is an experimental implementation, a few details need refining and may/will change in the future. In particular, the usage of some global or static variables should be replaced by thread variables, so that this becomes compatible with the usage of OS threads.

The details provided here are additional explanations to the comments found in the files NRE2.h and NRE2.c; in case of conflict, I guess the comments in those files take priority.

4.1 muThreads

The muThread structure is declared in NRE2.h; we maintain a circular list of threads, the manager will assign execution time to each of them following a simple round-robin policy - see details below:

    typedef struct muThread { 
        EvalFrame *evalFrameQPtr; /* The top EvalFrame in the thread's stack. */
        EvalFunction *evalFunPtr; /* The EvalFunction for the top EvalFrame. */
        int result; 
        struct muThread *next; 
        struct muThread *prev; 
        int flags;
    } muThread;

The flags indicate the current state of the muThread; for now, only the value TCL_MUTHREAD_BLOCKED is defined (and not used); this will have to be thought over when extensions that actually exploit this functionality are implemented.

A new muThread is created, linked into the list and made current by a call to Tcl_NewMuThread(); similarly, a call to Tcl_FreeMuThread() will remove the current thread - it should be called after cleaning it up.

The muThread system is initialized by the first call to Tcl_NewThread(); such a call is now made from Tcl_Main().

4.2 Evaluation and return function types

Evaluation and return functions have the same type, declared in NRE2.h:

    typedef struct EvalFrame *EvalFramePtr;
    typedef int EvalFunction _ANSI_ARGS_ ((int result, EvalFramePtr evalFramePtr));

Return functions should pop the eval frame before returning (see below on how to do that); otherwise, they will be called again. By the way, this provides an interesting mechanism for loop control - just do a conditional popping ...

4.3 EvalFrames

We define in NRE2.h the EvalFrame structure as a member of a linked list:

    typedef struct EvalFrame { 
        Tcl_Interp *interp; 
        EvalFunction *retFunPtr; /* function to call on return; continuation */ 
        struct EvalFrame *prev; /* previous EvalFrame in the muThread stack */ 
        void *data1; 
        void *data2; 
        void *data3; 
        void *data4; 
        void *data5; 
        void *data6; 
    } EvalFrame;

The data fields are set by the function that sets an EvalFrame. They serve the double purpose of passing arguments to the function that should eval the frame, as well as to the return function.

A new EvalFrame (already queued at the top of the current muThread's stack) is obtained as the return value of the function Tcl_PushEvalFrame(); a call to Tcl_PopEvalFrame() removes the current EvalFrame from the stack and returns to a pool of unused frames for reuse.

4.4 Flow Managers and evaluation requests

I do not think I can do a better job at explaining the functioning of the flow managers than directing the reader to look at the coding of Tcl_EvalFrames(evalFunPtr) in NRE2.c

A typical call to evaluate a frame in a new manager is in the body of the function EvalObjv (tclParse.c)

    evalFramePtr = Tcl_PushEvalFrame();

    evalFramePtr->interp = interp; 
    evalFramePtr->data1 = (void *) objc; 
    evalFramePtr->data2 = (void *) objv; 
    evalFramePtr->data3 = (void *) command; 
    evalFramePtr->data4 = (void *) length; 
    evalFramePtr->data5 = (void *) flags;

    return Tcl_EvalFrames(ObjvEvaluationEngine);

The non-recursive version TclEvalObjvNRE just directs the execution to a previous manager, by replacing the last line with

    Tcl_EvalFramesNRE(ObjvEvaluationEngine);

This particular example does not require any processing on return, so that the field evalFramePtr->retFunPtr retains its default NULL value.

4.5 Usage of GnuC's labels-as-values

The function TclExecuteByteCode (tclExecute.c) requires different entry points (currently three, more in the future) as it has to process also the return of iterative calls.

C does not provide the possibility of having different entry points to the same function (i.e., there is no analog to Fortran's ENTRY). The only solution to this conundrum is to program a switch on entry that directs to the correct section of the code. There are some problems with this approach (as compared to the labels-as-values approach described below):

Using labels-as-values, this can be implemented as an indirect jump: the EvalFrame contains the jump-address for reentry, instead of an integer value on which to switch. Both versions are implemented here, labels-as-values will be chosen when compiling with gcc.

4.6 Old interface and multiple managers

All public Tcl evaluation functions are implemented to call a new manager, so that they are safe for usage by functions that are not aware of NRE.


Next Previous Contents