Rob, as the HandleTable was your suggestion, could you provide a comment
on whether these patches are a practical way forward?
Jeff Latimer
Jeff Latimer wrote:
> These 2 patches implement HandleTables for tracking memory usage for
> the SCRIPT_STRING_ANALYSIS pointer. The problem is that the ssa can
> be copied to another pointer and NULL'ing the pointer is not a
> reliable means of de-allocating the pointer. The use of HandleTables
> looks like a solution to the problem but it depends on whether storing
> a handle in the ssa pointer is acceptable. The table is of fixed size
> which is another potential problem but tests indicate that the number
> of handles in use will remain relatively small by comparison to the
> table size.
>
> Advice is welcome.
>
> Jeff Latimer
>
> Changelog:
> Create HandleTables to keep track of memory allocation
> ---
> dlls/usp10/Makefile.in | 2 +
> dlls/usp10/usp10.c | 71
> +++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 70 insertions(+), 3 deletions(-)
> ------------------------------------------------------------------------
>
> diff --git a/dlls/usp10/Makefile.in b/dlls/usp10/Makefile.in
> index 9d716d5..edef33a 100644
> --- a/dlls/usp10/Makefile.in
> +++ b/dlls/usp10/Makefile.in
> @@ -4,7 +4,7 @@ SRCDIR = @srcdir@
> VPATH = @srcdir@
> MODULE = usp10.dll
> IMPORTLIB = libusp10.$(IMPLIBEXT)
> -IMPORTS = gdi32 kernel32
> +IMPORTS = gdi32 ntdll kernel32
>
> C_SRCS = \
> usp10.c
> diff --git a/dlls/usp10/usp10.c b/dlls/usp10/usp10.c
> index 9fd6c1e..4b15047 100644
> --- a/dlls/usp10/usp10.c
> +++ b/dlls/usp10/usp10.c
> @@ -30,6 +30,7 @@ #include "wingdi.h"
> #include "winuser.h"
> #include "winnls.h"
> #include "usp10.h"
> +#include "winternl.h"
>
> #include "wine/debug.h"
>
> @@ -73,17 +74,83 @@ typedef struct scriptcache {
> HDC hdc;
> } Scriptcache;
>
> +typedef struct _CACHE_HANDLE
> +{
> + RTL_HANDLE RtlHandle;
> + void * Cache_Address;
> +} CACHE_HANDLE;
> +
> +DWORD TlsIndex; /* Adress of shared memory */
> +
> /***********************************************************************
> * DllMain
> *
> + * In this DllMain storage is allocated to each thread so that a HandleTable can
> + * be created and maintained thread safe.
> + *
> + * NOTES
> + * The Tls functions (TlsAlloc, TlsSetValue, TlsGetValue and TlsFree) provide
> + * access to the local thread storage.
> + *
> + * LocalAlloc and LocalFree are used as in the Microsoft examples to access
> + * local thread storage.
> + *
> + * RtlInitializeHandleTable initialises the handle table to a fixed size of
> + * entries to contain the addresses of the cache pointers used in the
> + * ScriptString... functions. This function is fairly light weight as the
> + * space for the handle table entries is not allocated at this time but waits
> + * until the first RtlAllocateHandle call. Hence only the functions that need
> + * the handles incur the additional expense.
> */
> BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
> {
> + RTL_HANDLE_TABLE *Cache_HandleTable;
> + BOOL Return_flag;
> +
> switch(fdwReason) {
> + /*
> + * When the dll is loaded obtain a TlsIndex so that the HandleTable
> + * pointer can be stored there uniquely for each thread.
> + */
> case DLL_PROCESS_ATTACH:
> - DisableThreadLibraryCalls(hInstDLL);
> - break;
> + if ((TlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
> + return FALSE;
> + /* Fall though to THREAD_ATTACH as loading a DLL only drives
> + * DLL_PROCESS_ATTACHand not DLL_THREAD_ATTACH. Here we allocate space
> + * for the HandleTable from the thread local storage, save the pointer in
> + * the Tls and intialise the table.
> + */
> + case DLL_THREAD_ATTACH:
> + Cache_HandleTable = LocalAlloc(LPTR, sizeof(RTL_HANDLE_TABLE));
> + if (Cache_HandleTable)
> + {
> + Return_flag = TlsSetValue(TlsIndex, Cache_HandleTable);
> + RtlInitializeHandleTable(0x3FFF, sizeof(CACHE_HANDLE), Cache_HandleTable);
> + }
> + break;
> + /*
> + * At exit from a thread, clean up HandleTable which includes freeing the
> + * associated memory for handles and the HandleTable.
> + */
> + case DLL_THREAD_DETACH:
> + Cache_HandleTable = TlsGetValue(TlsIndex);
> + if (Cache_HandleTable)
> + {
> + RtlDestroyHandleTable(Cache_HandleTable);
> + LocalFree(Cache_HandleTable);
> + }
> + break;
> + /*
> + * As for DLL_THREAD_DETACH but includes freeing the TlsIndex.
> + */
> case DLL_PROCESS_DETACH:
> + Cache_HandleTable = TlsGetValue(TlsIndex);
> + if (Cache_HandleTable)
> + {
> + RtlDestroyHandleTable(Cache_HandleTable);
> + LocalFree(Cache_HandleTable);
> + }
> + TlsFree(TlsIndex);
> break;
> }
> return TRUE;
>
>
> ------------------------------------------------------------------------
>
>
>