C Examples -- Example 6: tclcs

### 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
         *
         */

        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 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
         * server.
         */
        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
Copyright © 1998-99 America Online, Inc.