Index: generic/nsfCmdDefinitions.c =================================================================== diff -u -N -r16a02881bff0a0d626d0045dfd96660338d0c314 -r760d5e6aa44c07331fea3c109385c309d906779c --- generic/nsfCmdDefinitions.c (.../nsfCmdDefinitions.c) (revision 16a02881bff0a0d626d0045dfd96660338d0c314) +++ generic/nsfCmdDefinitions.c (.../nsfCmdDefinitions.c) (revision 760d5e6aa44c07331fea3c109385c309d906779c) @@ -4,7 +4,7 @@ * Provide API for registering method definitions * and obtaining this data for introspection * - * Copyright (C) 2014 Gustaf Neumann + * Copyright (C) 2014-2016 Gustaf Neumann * * Vienna University of Economics and Business * Institute of Information Systems and New Media @@ -43,8 +43,153 @@ static int Register(Tcl_Interp *interp, Nsf_methodDefinition *methodDefinition); + /* + * Defintions for HashType cmdPtr. + * + * Background: since it is not guaranteed that sizeof(function pointer) == + * sizeof(data pointer) (or sizeof(function pointer) <= sizeof(data pointer)), + * passing function pointers via data pointers - which is the default tcl hash + * types do - is dangerous. So we define our own type that allows to hash on + * function pointers safely. + * + */ +static unsigned int CmdPtrKey(Tcl_HashTable *tablePtr, VOID *keyPtr); +static int CompareCmdPtrKeys(VOID *keyPtr, Tcl_HashEntry *hPtr); +static Tcl_HashEntry *AllocCmdPtrEntry(Tcl_HashTable *tablePtr, VOID *keyPtr); + +typedef struct cmdPtrEntry_t { + Tcl_ObjCmdProc *proc; +} cmdPtrEntry_t; + +static Tcl_HashKeyType cmdPtrHashKeyType = { + 1, /* version*/ + 0, /* flags */ + CmdPtrKey, /* hashKeyProc*/ + CompareCmdPtrKeys, /* compareKeysProc */ + AllocCmdPtrEntry, /* allocEntryProc */ + NULL, /* freeEntryProc */ +}; + +/* *---------------------------------------------------------------------- + * + * CmdPtrKey -- + * + * Compute a unsigned int hash value from a function pointer. + * + * Results: + * Hash value. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static unsigned int +CmdPtrKey( + Tcl_HashTable *tablePtr, /* Hash table. */ + VOID *keyPtr) /* Key from which to compute hash value. */ +{ + cmdPtrEntry_t *cmdEntryPtr = (cmdPtrEntry_t *)keyPtr; + Tcl_ObjCmdProc *value = cmdEntryPtr->proc; + + //fprintf(stderr, "=== hash from %p = %u // 0x%x\n", (void *)value, PTR2UINT(value), PTR2UINT(value)); + /* + * This is a very simple approach for obtaining a hash value. Maybe one + * needs a more sophisticated approach with wierd endians machines. + */ + return PTR2UINT(value); + + /* + as a reference: tcl's string hash functions + + register unsigned int result; + register int c; + result = 0; + + for (c=*string++ ; c ; c=*string++) { + result += (result<<3) + c; + } + return result; + */ +} + +/* + *---------------------------------------------------------------------- + * + * CompareCmdPtrKeys -- + * + * Compares two cmd ptr keys. + * + * Results: + * The return value is 0 if they are different and 1 if they are the + * same. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +CompareCmdPtrKeys( + VOID *keyPtr, /* New key to compare. */ + Tcl_HashEntry *hPtr) /* Existing key to compare. */ +{ + cmdPtrEntry_t *cmdEntryPtr = (cmdPtrEntry_t *)keyPtr; + Tcl_ObjCmdProc *existingValue; + + memcpy(&existingValue, &hPtr->key.oneWordValue, sizeof(Tcl_ObjCmdProc *)); + + //fprintf(stderr, "=== compare new %p existing %p\n", (void *)cmdPtr->proc, (void *)existingValue); + + return cmdEntryPtr->proc == existingValue; +} + +/* + *---------------------------------------------------------------------- + * + * AllocCmdPtrEntry -- + * + * Allocate space for a Tcl_HashEntry containing the cmd ptr + * + * Results: + * The return value is a pointer to the created entry. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static Tcl_HashEntry * +AllocCmdPtrEntry( + Tcl_HashTable *tablePtr, /* Hash table. */ + VOID *keyPtr) /* Key to store in the hash table entry. */ +{ + cmdPtrEntry_t *cmdEntryPtr = (cmdPtrEntry_t *)keyPtr; + Tcl_HashEntry *hPtr; + unsigned int size; + Tcl_ObjCmdProc *value = cmdEntryPtr->proc; + + size = sizeof(Tcl_HashEntry) + (sizeof(Tcl_ObjCmdProc *)) - sizeof(hPtr->key); + if (size < sizeof(Tcl_HashEntry)) { + size = sizeof(Tcl_HashEntry); + } + //fprintf(stderr, "=== alloc entry %p\n", (void *)value); + hPtr = (Tcl_HashEntry *) ckalloc(size); + + //fprintf(stderr, "=== trying to copy %ld bytes from %p to %p\n", sizeof(Tcl_ObjCmdProc *), (void *)value, &hPtr->key.oneWordValue); + memcpy(&hPtr->key.oneWordValue, &value, sizeof(Tcl_ObjCmdProc *)); + + hPtr->clientData = 0; + + return hPtr; +} + +/* + *---------------------------------------------------------------------- * Nsf_CmdDefinitionInit -- * * Initialize cmd definition structures @@ -65,13 +210,15 @@ NsfMutexLock(&cmdDefinitonMutex); if (cmdDefinitonRefCount == 0) { - Tcl_InitHashTable(cmdDefinitonHashTablePtr, TCL_ONE_WORD_KEYS); + // Tcl_InitHashTable(cmdDefinitonHashTablePtr, TCL_ONE_WORD_KEYS); + Tcl_InitCustomHashTable(cmdDefinitonHashTablePtr, TCL_CUSTOM_PTR_KEYS, &cmdPtrHashKeyType); } cmdDefinitonRefCount++; NsfMutexUnlock(&cmdDefinitonMutex); } + /* *---------------------------------------------------------------------- * Nsf_CmdDefinitionRegister -- @@ -117,11 +264,15 @@ Nsf_methodDefinition * Nsf_CmdDefinitionGet(Tcl_ObjCmdProc *proc) { Tcl_HashEntry *hPtr; + cmdPtrEntry_t cmdEntry; nonnull_assert(proc != NULL); + //fprintf(stderr, "=== Lookup proc %p\n", proc); + cmdEntry.proc = proc; + NsfMutexLock(&cmdDefinitonMutex); - hPtr = Tcl_FindHashEntry(cmdDefinitonHashTablePtr, (char *)proc); + hPtr = Tcl_FindHashEntry(cmdDefinitonHashTablePtr, (const char *)&cmdEntry); NsfMutexUnlock(&cmdDefinitonMutex); if (hPtr != NULL) { @@ -151,12 +302,15 @@ Register(Tcl_Interp *interp, Nsf_methodDefinition *methodDefinition) { Tcl_HashEntry *hPtr; int isNew; + cmdPtrEntry_t cmdEntry; nonnull_assert(interp != NULL); nonnull_assert(methodDefinition != NULL); + //fprintf(stderr, "=== Register proc %p with name %s\n", methodDefinition->proc, methodDefinition->methodName); + cmdEntry.proc = methodDefinition->proc; NsfMutexLock(&cmdDefinitonMutex); - hPtr = Tcl_CreateHashEntry(cmdDefinitonHashTablePtr, (char *)methodDefinition->proc, &isNew); + hPtr = Tcl_CreateHashEntry(cmdDefinitonHashTablePtr, (const char *)&cmdEntry, &isNew); NsfMutexUnlock(&cmdDefinitonMutex); if (isNew != 0) {