[ Previous ] [ Contents ] [ Index ] [ Next ]

Example 6: tclcs

The following example adds critical section enter and leave commands to Tcl. This allows you to protect shared resources (i.e., an external file or remote connection) accessed in a Tcl script.

This example can be found in the examples/c/tclcs directory.

    
    #include "ns.h"
    #include "nstcl.h"
    
    /*
     * This code implements simple critical section primitives as TCL commands 
     * within the AOLserver.  To use this module, add the following to the 
     * [ns\server\server-name\modules] section of your nsd.ini file:
     * cs=tclcs.dll    ; or tclcs.so on Unix platforms
     * 
     * Within your TCL, these commands should be used as follows:
     *      ...
     *      cs_enter
     *      set err [catch {some tcl}]
     *      cs_leave
     *      if $err {
     *              error $err
     *      }
     *      ...
     * Note that any error should be caught to avoid leaving the
     * critical section in the locked state after the script exits.
     * 
     * Also, because the init function uses the module name to construct
     * the command names,  you can load the module multiple times if you
     * need more than one critical section.  For example, if you needed 2
     * critical sections, your nsd.ini would have:
     *
     * [ns\server\server-name\modules]
     * cs1=tclcs.dll
     * cs2=tclcs.dll
     *
     * and then, in your Tcl script, you would access the two critical
     * sections using their unique names:
     *
     *	...
     *	cs1_enter
     *	... access resource protected by cs 1 ...
     * 	cs2_enter
     * 	... access resource 2, leaving resource 1 locked ...
     * 	cs2_leave
     * 	cs1_leave
     * 	
     */
    
    DllExport int Ns_ModuleVersion = 1;
    
    static int InitCs(Tcl_Interp *interp, void *ctx);
    static Tcl_CmdProc EnterCs, LeaveCs;
    
    /*
     * This structure is used to pass the critical section
     * and enter and leave command names to InitCs function
     * through the Ns_TclInitInterps function.
     */
    typedef struct {
    	char *enter;
    	char *leave;
    	Ns_CriticalSection *cs;
    } CsCtx;
    
    
    /*
     * Ns_ModuleInit - The function is called each time the
     * tclcs module is loaded into a virtual server.  It
     * constructs the names of the enter and leave Tcl commands
     * from the module name and then calls Ns_TclInitInterps
     * to add the command to each interpreter of the virtual
     * server.
     */
    DllExport int
    Ns_ModuleInit(char *hServer, char *hModule)
    {
    	Ns_DString dsEnter;
    	Ns_DString dsLeave;
    	CsCtx ctx;
    	int status;
    
    	Ns_DStringInit(&dsEnter);
    	Ns_DStringAppend(&dsEnter, hModule);
    	Ns_DStringAppend(&dsEnter, "_enter");
    
    	Ns_DStringInit(&dsLeave);
    	Ns_DStringAppend(&dsLeave, hModule);
    	Ns_DStringAppend(&dsLeave, "_leave");
    
    	ctx.enter = dsEnter.string;
    	ctx.leave = dsLeave.string;
            ctx.cs = ns_malloc(sizeof(Ns_CriticalSection));
            Ns_InitializeCriticalSection(ctx.cs);
    
            status = Ns_TclInitInterps(hServer, InitCs, (void *) &ctx);
    
    	Ns_DStringFree(&dsEnter);
    	Ns_DStringFree(&dsLeave);
    	return status;
    }
            
    
    /*
     * InitCs - Initialize a single Tcl interpreter with the
     * critical section enter and leave commands.
     */
    static int
    InitCs(Tcl_Interp *interp, void *ctx)
    {
    	CsCtx *csctx;
    
    	csctx = ctx;
            Tcl_CreateCommand(interp, csctx->enter, EnterCs, 
                                                        (ClientData) csctx->cs, NULL);
            Tcl_CreateCommand(interp, csctx->leave, LeaveCs, 
                                                        (ClientData) csctx->cs, NULL);
            return TCL_OK;
    }
    
    
    /* 
     * EnterCs - Enter the critical section passed in as callback data.
     */
    static int
    EnterCs(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
    {
            Ns_CriticalSection *cs = (Ns_CriticalSection *) clientData;
    
            Ns_EnterCriticalSection(cs);
            return TCL_OK;
    }
    
    
    /* 
     * LeaveCs - Leave the critical section passed in as callback data.
     */
    static int
    LeaveCs(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
    {
            Ns_CriticalSection *cs = (Ns_CriticalSection *) clientData;
    
            Ns_LeaveCriticalSection(cs);
            return TCL_OK;
    }

Top of Page

[ Previous ] [ Contents ] [ Index ] [ Next ]
Copyright © 1996 America Online, Inc.