226 lines
7.5 KiB
C
226 lines
7.5 KiB
C
|
/*
|
||
|
* This is the header file for the module that implements shared variables.
|
||
|
* for protected multithreaded access.
|
||
|
*
|
||
|
* Copyright (c) 2002 by Zoran Vasiljevic.
|
||
|
*
|
||
|
* See the file "license.txt" for information on usage and redistribution
|
||
|
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||
|
* ---------------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
#ifndef _SV_H_
|
||
|
#define _SV_H_
|
||
|
|
||
|
#include <tcl.h>
|
||
|
#include <ctype.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "threadSpCmd.h" /* For recursive locks */
|
||
|
|
||
|
/*
|
||
|
* Uncomment following line to get command-line
|
||
|
* compatibility with AOLserver nsv_* commands
|
||
|
*/
|
||
|
|
||
|
/* #define NSV_COMPAT 1 */
|
||
|
|
||
|
/*
|
||
|
* Uncomment following line to force command-line
|
||
|
* compatibility with older thread::sv_ commands.
|
||
|
*/
|
||
|
|
||
|
/* #define OLD_COMPAT 1 */
|
||
|
|
||
|
#ifdef NSV_COMPAT
|
||
|
# define TSV_CMD2_PREFIX "nsv_" /* Compatiblity prefix for NaviServer/AOLserver */
|
||
|
#else
|
||
|
# define TSV_CMD2_PREFIX "sv_" /* Regular command prefix for NaviServer/AOLserver */
|
||
|
#endif
|
||
|
#ifdef OLD_COMPAT
|
||
|
# define TSV_CMD_PREFIX "thread::sv_" /* Old command prefix for Tcl */
|
||
|
#else
|
||
|
# define TSV_CMD_PREFIX "tsv::" /* Regular command prefix for Tcl */
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* Used when creating arrays/variables
|
||
|
*/
|
||
|
|
||
|
#define FLAGS_CREATEARRAY 1 /* Create the array in bucket if none found */
|
||
|
#define FLAGS_NOERRMSG 2 /* Do not format error message */
|
||
|
#define FLAGS_CREATEVAR 4 /* Create the array variable if none found */
|
||
|
|
||
|
/*
|
||
|
* Macros for handling locking and unlocking
|
||
|
*/
|
||
|
#define LOCK_BUCKET(a) Sp_RecursiveMutexLock(&(a)->lock)
|
||
|
#define UNLOCK_BUCKET(a) Sp_RecursiveMutexUnlock(&(a)->lock)
|
||
|
|
||
|
#define LOCK_CONTAINER(a) Sp_RecursiveMutexLock(&(a)->bucketPtr->lock)
|
||
|
#define UNLOCK_CONTAINER(a) Sp_RecursiveMutexUnlock(&(a)->bucketPtr->lock)
|
||
|
|
||
|
/*
|
||
|
* This is named synetrically to LockArray as function
|
||
|
* rather than as a macro just to improve readability.
|
||
|
*/
|
||
|
|
||
|
#define UnlockArray(a) UNLOCK_CONTAINER(a)
|
||
|
|
||
|
/*
|
||
|
* Mode for Sv_PutContainer, so it knows what
|
||
|
* happened with the embedded shared object.
|
||
|
*/
|
||
|
|
||
|
#define SV_UNCHANGED 0 /* Object has not been modified */
|
||
|
#define SV_CHANGED 1 /* Object has been modified */
|
||
|
#define SV_ERROR -1 /* Object may be in incosistent state */
|
||
|
|
||
|
/*
|
||
|
* Definitions of functions implementing simple key/value
|
||
|
* persistent storage for shared variable arrays.
|
||
|
*/
|
||
|
|
||
|
typedef ClientData (ps_open_proc)(const char*);
|
||
|
|
||
|
typedef int (ps_get_proc) (ClientData, const char*, char**, size_t*);
|
||
|
typedef int (ps_put_proc) (ClientData, const char*, char*, size_t);
|
||
|
typedef int (ps_first_proc) (ClientData, char**, char**, size_t*);
|
||
|
typedef int (ps_next_proc) (ClientData, char**, char**, size_t*);
|
||
|
typedef int (ps_delete_proc)(ClientData, const char*);
|
||
|
typedef int (ps_close_proc) (ClientData);
|
||
|
typedef void(ps_free_proc) (ClientData, void*);
|
||
|
|
||
|
typedef const char* (ps_geterr_proc)(ClientData);
|
||
|
|
||
|
/*
|
||
|
* This structure maintains a bunch of pointers to functions implementing
|
||
|
* the simple persistence layer for the shared variable arrays.
|
||
|
*/
|
||
|
|
||
|
typedef struct PsStore {
|
||
|
const char *type; /* Type identifier of the persistent storage */
|
||
|
ClientData psHandle; /* Handle to the opened storage */
|
||
|
ps_open_proc *psOpen; /* Function to open the persistent key store */
|
||
|
ps_get_proc *psGet; /* Function to retrieve value bound to key */
|
||
|
ps_put_proc *psPut; /* Function to store user key and value */
|
||
|
ps_first_proc *psFirst; /* Function to retrieve the first key/value */
|
||
|
ps_next_proc *psNext; /* Function to retrieve the next key/value */
|
||
|
ps_delete_proc *psDelete; /* Function to delete user key and value */
|
||
|
ps_close_proc *psClose; /* Function to close the persistent store */
|
||
|
ps_free_proc *psFree; /* Fuction to free allocated memory */
|
||
|
ps_geterr_proc *psError; /* Function to return last store error */
|
||
|
struct PsStore *nextPtr; /* For linking into linked lists */
|
||
|
} PsStore;
|
||
|
|
||
|
/*
|
||
|
* The following structure defines a collection of arrays.
|
||
|
* Only the arrays within a given bucket share a lock,
|
||
|
* allowing for more concurency.
|
||
|
*/
|
||
|
|
||
|
typedef struct Bucket {
|
||
|
Sp_RecursiveMutex lock; /* */
|
||
|
Tcl_HashTable arrays; /* Hash table of all arrays in bucket */
|
||
|
Tcl_HashTable handles; /* Hash table of given-out handles in bucket */
|
||
|
struct Container *freeCt; /* List of free Tcl-object containers */
|
||
|
} Bucket;
|
||
|
|
||
|
/*
|
||
|
* The following structure maintains the context for each variable array.
|
||
|
*/
|
||
|
|
||
|
typedef struct Array {
|
||
|
char *bindAddr; /* Array is bound to this address */
|
||
|
PsStore *psPtr; /* Persistent storage functions */
|
||
|
Bucket *bucketPtr; /* Array bucket. */
|
||
|
Tcl_HashEntry *entryPtr; /* Entry in bucket array table. */
|
||
|
Tcl_HashEntry *handlePtr; /* Entry in handles table */
|
||
|
Tcl_HashTable vars; /* Table of variables. */
|
||
|
} Array;
|
||
|
|
||
|
/*
|
||
|
* The object container for Tcl-objects stored within shared arrays.
|
||
|
*/
|
||
|
|
||
|
typedef struct Container {
|
||
|
Bucket *bucketPtr; /* Bucket holding the array below */
|
||
|
Array *arrayPtr; /* Array with the object container*/
|
||
|
Tcl_HashEntry *entryPtr; /* Entry in array table. */
|
||
|
Tcl_HashEntry *handlePtr; /* Entry in handles table */
|
||
|
Tcl_Obj *tclObj; /* Tcl object to hold shared values */
|
||
|
int epoch; /* Track object changes */
|
||
|
char *chunkAddr; /* Address of one chunk of object containers */
|
||
|
struct Container *nextPtr; /* Next object container in the free list */
|
||
|
int aolSpecial;
|
||
|
} Container;
|
||
|
|
||
|
/*
|
||
|
* Structure for generating command names in Tcl
|
||
|
*/
|
||
|
|
||
|
typedef struct SvCmdInfo {
|
||
|
char *name; /* The short name of the command */
|
||
|
char *cmdName; /* Real (rewritten) name of the command */
|
||
|
char *cmdName2; /* Real AOL (rewritten) name of the command */
|
||
|
Tcl_ObjCmdProc *objProcPtr; /* The object-based command procedure */
|
||
|
Tcl_CmdDeleteProc *delProcPtr; /* Pointer to command delete function */
|
||
|
struct SvCmdInfo *nextPtr; /* Next in chain of registered commands */
|
||
|
int aolSpecial;
|
||
|
} SvCmdInfo;
|
||
|
|
||
|
/*
|
||
|
* Structure for registering special object duplicator functions.
|
||
|
* Reason for this is that even some regular Tcl duplicators
|
||
|
* produce shallow instead of proper deep copies of the object.
|
||
|
* While this is considered to be ok in single-threaded apps,
|
||
|
* a multithreaded app could have problems when accessing objects
|
||
|
* which live in (i.e. are accessed from) different interpreters.
|
||
|
* So, for each object type which should be stored in shared object
|
||
|
* pools, we must assure that the object is copied properly.
|
||
|
*/
|
||
|
|
||
|
typedef struct RegType {
|
||
|
const Tcl_ObjType *typePtr; /* Type of the registered object */
|
||
|
Tcl_DupInternalRepProc *dupIntRepProc; /* Special deep-copy duper */
|
||
|
struct RegType *nextPtr; /* Next in chain of registered types */
|
||
|
} RegType;
|
||
|
|
||
|
/*
|
||
|
* Limited API functions
|
||
|
*/
|
||
|
|
||
|
MODULE_SCOPE void
|
||
|
Sv_RegisterCommand(const char*,Tcl_ObjCmdProc*,Tcl_CmdDeleteProc*, int);
|
||
|
|
||
|
MODULE_SCOPE void
|
||
|
Sv_RegisterObjType(const Tcl_ObjType*, Tcl_DupInternalRepProc*);
|
||
|
|
||
|
MODULE_SCOPE void
|
||
|
Sv_RegisterPsStore(const PsStore*);
|
||
|
|
||
|
MODULE_SCOPE int
|
||
|
Sv_GetContainer(Tcl_Interp*,int,Tcl_Obj*const objv[],Container**,int*,int);
|
||
|
|
||
|
MODULE_SCOPE int
|
||
|
Sv_PutContainer(Tcl_Interp*, Container*, int);
|
||
|
|
||
|
/*
|
||
|
* Private version of Tcl_DuplicateObj which takes care about
|
||
|
* copying objects when loaded to and retrieved from shared array.
|
||
|
*/
|
||
|
|
||
|
MODULE_SCOPE Tcl_Obj* Sv_DuplicateObj(Tcl_Obj*);
|
||
|
|
||
|
#endif /* _SV_H_ */
|
||
|
|
||
|
/* EOF $RCSfile: threadSvCmd.h,v $ */
|
||
|
|
||
|
/* Emacs Setup Variables */
|
||
|
/* Local Variables: */
|
||
|
/* mode: C */
|
||
|
/* indent-tabs-mode: nil */
|
||
|
/* c-basic-offset: 4 */
|
||
|
/* End: */
|
||
|
|