Attachment "temp-dir-cleanup.patch" to
ticket [5c7578d0f2]
added by
chw
2016-05-03 21:09:38.
Temporary directory cleanup on Windows for DLLs loaded from Tclkits etc.
diff -Nur tcl8.6.5.orig/generic/tclEvent.c tcl8.6.5/generic/tclEvent.c
--- tcl8.6.5.orig/generic/tclEvent.c 2016-02-25 21:12:37.000000000 +0100
+++ tcl8.6.5/generic/tclEvent.c 2016-05-03 23:13:19.997528991 +0200
@@ -985,6 +985,13 @@
*/
FinalizeThread(/* quick */ 1);
+
+#ifdef _WIN32
+ /*
+ * Try at least to cleanup temporary DLLs when using VFSes.
+ */
+ TclFinalizeLoad();
+#endif
}
TclpExit(status);
Tcl_Panic("OS exit failed!");
diff -Nur tcl8.6.5.orig/generic/tclInt.h tcl8.6.5/generic/tclInt.h
--- tcl8.6.5.orig/generic/tclInt.h 2016-02-25 21:12:37.000000000 +0100
+++ tcl8.6.5/generic/tclInt.h 2016-05-03 23:12:35.507371431 +0200
@@ -3043,6 +3043,7 @@
MODULE_SCOPE void TclpFinalizeMutex(Tcl_Mutex *mutexPtr);
MODULE_SCOPE void TclpFinalizePipes(void);
MODULE_SCOPE void TclpFinalizeSockets(void);
+MODULE_SCOPE void TclpFinalizeLoad(void);
MODULE_SCOPE int TclCreateSocketAddress(Tcl_Interp *interp,
struct addrinfo **addrlist,
const char *host, int port, int willBind,
diff -Nur tcl8.6.5.orig/generic/tclLoad.c tcl8.6.5/generic/tclLoad.c
--- tcl8.6.5.orig/generic/tclLoad.c 2016-02-25 21:12:37.000000000 +0100
+++ tcl8.6.5/generic/tclLoad.c 2016-05-01 14:48:49.244997000 +0200
@@ -1168,6 +1168,7 @@
ckfree(pkgPtr->packageName);
ckfree(pkgPtr);
}
+ TclpFinalizeLoad();
}
/*
diff -Nur tcl8.6.5.orig/generic/tclLoadNone.c tcl8.6.5/generic/tclLoadNone.c
--- tcl8.6.5.orig/generic/tclLoadNone.c 2016-02-25 21:12:37.000000000 +0100
+++ tcl8.6.5/generic/tclLoadNone.c 2016-05-01 14:54:32.871644000 +0200
@@ -121,6 +121,28 @@
#endif /* TCL_LOAD_FROM_MEMORY */
/*
+ *----------------------------------------------------------------------
+ *
+ * TclpFinalizeLoad --
+ *
+ * On process termination, cleanup and finally remove the
+ * directory used for temporary copies of DLLs.
+ *
+ * Results:
+ * None.
+ *
+ * Side-effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclpFinalizeLoad(void)
+{
+}
+
+/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff -Nur tcl8.6.5.orig/unix/tclLoadDl.c tcl8.6.5/unix/tclLoadDl.c
--- tcl8.6.5.orig/unix/tclLoadDl.c 2016-02-25 21:12:38.000000000 +0100
+++ tcl8.6.5/unix/tclLoadDl.c 2016-05-03 23:14:50.038896663 +0200
@@ -266,6 +266,28 @@
}
/*
+ *----------------------------------------------------------------------
+ *
+ * TclpFinalizeLoad --
+ *
+ * On process termination, cleanup and finally remove the
+ * directory used for temporary copies of DLLs.
+ *
+ * Results:
+ * None.
+ *
+ * Side-effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclpFinalizeLoad(void)
+{
+}
+
+/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff -Nur tcl8.6.5.orig/unix/tclLoadDyld.c tcl8.6.5/unix/tclLoadDyld.c
--- tcl8.6.5.orig/unix/tclLoadDyld.c 2016-02-25 21:12:38.000000000 +0100
+++ tcl8.6.5/unix/tclLoadDyld.c 2016-05-03 23:14:56.048188049 +0200
@@ -709,6 +709,28 @@
#endif /* TCL_LOAD_FROM_MEMORY */
/*
+ *----------------------------------------------------------------------
+ *
+ * TclpFinalizeLoad --
+ *
+ * On process termination, cleanup and finally remove the
+ * directory used for temporary copies of DLLs.
+ *
+ * Results:
+ * None.
+ *
+ * Side-effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclpFinalizeLoad(void)
+{
+}
+
+/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff -Nur tcl8.6.5.orig/unix/tclLoadNext.c tcl8.6.5/unix/tclLoadNext.c
--- tcl8.6.5.orig/unix/tclLoadNext.c 2016-02-25 21:12:38.000000000 +0100
+++ tcl8.6.5/unix/tclLoadNext.c 2016-05-03 23:15:02.000476864 +0200
@@ -209,6 +209,28 @@
}
/*
+ *----------------------------------------------------------------------
+ *
+ * TclpFinalizeLoad --
+ *
+ * On process termination, cleanup and finally remove the
+ * directory used for temporary copies of DLLs.
+ *
+ * Results:
+ * None.
+ *
+ * Side-effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclpFinalizeLoad(void)
+{
+}
+
+/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff -Nur tcl8.6.5.orig/unix/tclLoadOSF.c tcl8.6.5/unix/tclLoadOSF.c
--- tcl8.6.5.orig/unix/tclLoadOSF.c 2016-02-25 21:12:38.000000000 +0100
+++ tcl8.6.5/unix/tclLoadOSF.c 2016-05-03 23:15:07.274732696 +0200
@@ -227,6 +227,28 @@
}
/*
+ *----------------------------------------------------------------------
+ *
+ * TclpFinalizeLoad --
+ *
+ * On process termination, cleanup and finally remove the
+ * directory used for temporary copies of DLLs.
+ *
+ * Results:
+ * None.
+ *
+ * Side-effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclpFinalizeLoad(void)
+{
+}
+
+/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff -Nur tcl8.6.5.orig/unix/tclLoadShl.c tcl8.6.5/unix/tclLoadShl.c
--- tcl8.6.5.orig/unix/tclLoadShl.c 2016-02-25 21:12:38.000000000 +0100
+++ tcl8.6.5/unix/tclLoadShl.c 2016-05-03 23:15:13.304025295 +0200
@@ -216,6 +216,28 @@
}
/*
+ *----------------------------------------------------------------------
+ *
+ * TclpFinalizeLoad --
+ *
+ * On process termination, cleanup and finally remove the
+ * directory used for temporary copies of DLLs.
+ *
+ * Results:
+ * None.
+ *
+ * Side-effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclpFinalizeLoad(void)
+{
+}
+
+/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff -Nur tcl8.6.5.orig/win/tclWinLoad.c tcl8.6.5/win/tclWinLoad.c
--- tcl8.6.5.orig/win/tclWinLoad.c 2016-02-25 21:12:38.000000000 +0100
+++ tcl8.6.5/win/tclWinLoad.c 2016-05-02 03:21:04.647886000 +0200
@@ -21,6 +21,7 @@
static WCHAR *dllDirectoryName = NULL;
static Tcl_Mutex dllDirectoryNameMutex;
+static Tcl_HashTable tempDllTable;
/*
* Static functions defined within this file.
@@ -148,6 +149,22 @@
handlePtr->unloadFileProcPtr = &UnloadFile;
*loadHandle = handlePtr;
*unloadProcPtr = &UnloadFile;
+
+ /*
+ * Remember handle for process termination cleanup handler
+ * if the DLL is a copy in temporary directory.
+ */
+
+ Tcl_MutexLock(&dllDirectoryNameMutex);
+ if (dllDirectoryName != NULL) {
+ int dummy, len = wcslen(dllDirectoryName);
+
+ if ((len > 0) && (_wcsnicmp(nativeName, dllDirectoryName, len) == 0)) {
+ Tcl_CreateHashEntry(&tempDllTable, (ClientData) handlePtr, &dummy);
+ }
+ }
+ Tcl_MutexUnlock(&dllDirectoryNameMutex);
+
return TCL_OK;
}
@@ -225,9 +242,27 @@
* that represents the loaded file. */
{
HINSTANCE hInstance = (HINSTANCE) loadHandle->clientData;
+ BOOL success, keep = 0;
- FreeLibrary(hInstance);
- ckfree(loadHandle);
+ success = FreeLibrary(hInstance);
+ Tcl_MutexLock(&dllDirectoryNameMutex);
+ if (dllDirectoryName != NULL) {
+ Tcl_HashEntry *hPtr =
+ Tcl_FindHashEntry(&tempDllTable, (ClientData) loadHandle);
+
+ if (hPtr != NULL) {
+ if (success) {
+ Tcl_DeleteHashEntry(hPtr);
+ } else {
+ /* FreeLibrary() will be retried in TclpFinalizeLoad() later */
+ keep = 1;
+ }
+ }
+ }
+ Tcl_MutexUnlock(&dllDirectoryNameMutex);
+ if (!keep) {
+ ckfree(loadHandle);
+ }
}
/*
@@ -317,6 +352,95 @@
/*
*----------------------------------------------------------------------
*
+ * TclpFinalizeLoad --
+ *
+ * On process termination, cleanup and finally remove the
+ * directory used for temporary copies of DLLs.
+ *
+ * Results:
+ * None.
+ *
+ * Side-effects:
+ * Delete files in temp directory.
+ * Remove temp directory.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclpFinalizeLoad(void)
+{
+ WCHAR *dllDir = NULL;
+ int dllDirLen;
+ Tcl_DString ds;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ HANDLE handle;
+ WIN32_FIND_DATAW data;
+
+ if (!TclFullFinalizationRequested()) {
+ Tcl_MutexLock(&dllDirectoryNameMutex);
+ }
+ if (dllDirectoryName != NULL) {
+ dllDir = dllDirectoryName;
+ dllDirectoryName = NULL;
+ }
+ if (dllDir != NULL) {
+
+ /*
+ * Try unloading left-over DLLs.
+ */
+
+ hPtr = Tcl_FirstHashEntry(&tempDllTable, &search);
+ while (hPtr != NULL) {
+ Tcl_LoadHandle loadHandle =
+ (Tcl_LoadHandle) Tcl_GetHashKey(&tempDllTable, hPtr);
+
+ Tcl_DeleteHashEntry(hPtr);
+ hPtr = Tcl_NextHashEntry(&search);
+
+ /*
+ * Same cleanup steps as in UnloadFile(), but dangerous anyway.
+ */
+
+ FreeLibrary((HINSTANCE) loadHandle->clientData);
+ ckfree(loadHandle);
+ }
+ Tcl_DeleteHashTable(&tempDllTable);
+
+ /*
+ * Delete temporary copies of DLLs, then the temporary directory.
+ */
+
+ Tcl_DStringInit(&ds);
+ dllDirLen = wcslen(dllDir) * sizeof (WCHAR);
+ Tcl_DStringAppend(&ds, (char *) dllDir, dllDirLen);
+ Tcl_DStringAppend(&ds, (char *) L"\\*.dll\0",
+ wcslen(L"\\*.dll\0") * sizeof (WCHAR));
+ dllDirLen += sizeof (WCHAR); /* include trailing backslash */
+ handle = FindFirstFileW((WCHAR *) Tcl_DStringValue(&ds), &data);
+ if (handle != INVALID_HANDLE_VALUE) {
+ do {
+ Tcl_DStringSetLength(&ds, dllDirLen);
+ Tcl_DStringAppend(&ds, (char *) data.cFileName,
+ wcslen(data.cFileName) * sizeof (WCHAR));
+ Tcl_DStringAppend(&ds, (char *) L"\0", sizeof (WCHAR));
+ DeleteFileW((WCHAR *) Tcl_DStringValue(&ds));
+ } while (FindNextFileW(handle, &data) == TRUE);
+ FindClose(handle);
+ }
+ Tcl_DStringFree(&ds);
+ RemoveDirectoryW(dllDir);
+ ckfree(dllDir);
+ }
+ if (!TclFullFinalizationRequested()) {
+ Tcl_MutexUnlock(&dllDirectoryNameMutex);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* InitDLLDirectoryName --
*
* Helper for TclpTempFileNameForLibrary; builds a temporary directory
@@ -390,6 +514,7 @@
copyToGlobalBuffer:
dllDirectoryName = ckalloc((nameLen+1) * sizeof(WCHAR));
wcscpy(dllDirectoryName, name);
+ Tcl_InitHashTable(&tempDllTable, TCL_ONE_WORD_KEYS);
return TCL_OK;
}