Tcl Source Code

Artifact [3e24de9a84]
Login

Artifact 3e24de9a84172f524c78c4e2852f79ab6ed536db:

Attachment "tclIOUtil.c.patch" to ticket [753315ffff] added by vasiljevic 2003-06-22 22:35:39.
--- generic/tclIOUtil.c.orig	Fri Jun 20 10:36:18 2003
+++ generic/tclIOUtil.c	Sun Jun 22 16:06:41 2003
@@ -49,6 +49,9 @@
     struct FilesystemRecord *nextPtr;  
 				  /* The next filesystem registered
 				   * to Tcl, or NULL if no more. */
+    struct FilesystemRecord *prevPtr;  
+				  /* The previous filesystem registered
+				   * to Tcl, or NULL if no more. */
 } FilesystemRecord;
 
 /* 
@@ -68,12 +71,11 @@
 		Tcl_Obj *objPtr, Tcl_Obj *cwdPtr));
 Tcl_Obj* TclFSInternalToNormalized _ANSI_ARGS_((
 		Tcl_Filesystem *fromFilesystem, ClientData clientData,
-		FilesystemRecord **fsRecPtrPtr, int *epochPtr));
-int      TclFSEnsureEpochOk _ANSI_ARGS_((Tcl_Obj* pathObjPtr, int theEpoch, 
+		FilesystemRecord **fsRecPtrPtr));
+int      TclFSEnsureEpochOk _ANSI_ARGS_((Tcl_Obj* pathObjPtr,
 		Tcl_Filesystem **fsPtrPtr));
 void     TclFSSetPathDetails _ANSI_ARGS_((Tcl_Obj *pathObjPtr, 
-		FilesystemRecord *fsRecPtr, ClientData clientData, 
-		int theEpoch));
+		FilesystemRecord *fsRecPtr, ClientData clientData)); 
 
 /* 
  * Private variables for use in this file
@@ -98,10 +100,13 @@
  * Prototypes for procedures defined later in this file.
  */
 
-static FilesystemRecord* FsGetIterator(void);
-static void FsReleaseIterator(void);
+static FilesystemRecord* FsGetFirstFilesystem(void);
 static void FsThrExitProc(ClientData cd);
 
+#ifdef TCL_THREADS
+static void FsRecacheFilesystemList(void);
+#endif
+
 /* 
  * These form part of the native filesystem support.  They are needed
  * here because we have a few native filesystem functions (which are
@@ -450,55 +455,44 @@
 };
 
 /* 
- * The following few variables are protected by the 
- * filesystemMutex just below.
- */
-
-/* 
  * This is incremented each time we modify the linked list of
  * filesystems.  Any time it changes, all cached filesystem
  * representations are suspect and must be freed.
+ * For multithreading builds, change of the filesystem epoch
+ * will trigger cache cleanup in all threads.  
  */
 int theFilesystemEpoch = 0;
 
 /*
- * Stores the linked list of filesystems.
+ * Stores the linked list of filesystems. A 1:1 copy of this
+ * list is also maintained in the TSD for each thread. This
+ * is to avoid synchronization issues.
  */
 static FilesystemRecord *filesystemList = &nativeFilesystemRecord;
 
-/* 
- * The number of loops which are currently iterating over the linked
- * list.  If this is greater than zero, we can't modify the list.
- */
-static int filesystemIteratorsInProgress = 0;
-
-/*
- * Someone wants to modify the list of filesystems if this is set.
- */
-static int filesystemWantToModify = 0;
-
-#ifdef TCL_THREADS
-static Tcl_Condition filesystemOkToModify = NULL;
-#endif
-
 TCL_DECLARE_MUTEX(filesystemMutex)
 
 /* 
  * Used to implement Tcl_FSGetCwd in a file-system independent way.
- * This is protected by the cwdMutex below.
  */
 static Tcl_Obj* cwdPathPtr = NULL;
 static int cwdPathEpoch = 0;
 TCL_DECLARE_MUTEX(cwdMutex)
 
 /*
- * This structure holds per-thread private copy of the
- * current directory maintained by the global cwdPathPtr.
+ * This structure holds per-thread private copies of
+ * some global data. This way we avoid most of the
+ * synchronization calls which boosts performance, at
+ * cost of having to update this information each
+ * time the corresponding epoch counter changes.
+ * 
  */
 typedef struct ThreadSpecificData {
     int initialized;
     int cwdPathEpoch;
+    int filesystemEpoch; 
     Tcl_Obj *cwdPathPtr;
+    FilesystemRecord *filesystemList;
 } ThreadSpecificData;
 
 Tcl_ThreadDataKey dataKey;
@@ -532,9 +526,21 @@
     ClientData cd;
 {
     ThreadSpecificData *tsdPtr = (ThreadSpecificData*)cd;
+    FilesystemRecord *fsRecPtr = NULL, *tmpFsRecPtr = NULL;
+
+    /* Trash the cwd copy */
     if (tsdPtr->cwdPathPtr != NULL) {
 	Tcl_DecrRefCount(tsdPtr->cwdPathPtr);
     }
+    /* Trash the filesystems cache */
+    fsRecPtr = tsdPtr->filesystemList;
+    while (fsRecPtr != NULL) {
+	tmpFsRecPtr = fsRecPtr->nextPtr;
+	if (--fsRecPtr->fileRefCount <= 0) {
+	    ckfree((char *)fsRecPtr);
+	}
+	fsRecPtr = tmpFsRecPtr;
+    }
 }
 
 int 
@@ -544,52 +550,103 @@
     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
 
     Tcl_MutexLock(&cwdMutex);
-    if (tsdPtr->initialized == 0) {
-	Tcl_CreateThreadExitHandler(FsThrExitProc, (ClientData)tsdPtr);
-	tsdPtr->initialized = 1;
-    }
     if (tsdPtr->cwdPathPtr == NULL) {
-        if (cwdPathPtr == NULL) {
-    	    tsdPtr->cwdPathPtr = NULL;
-        } else {
-    	    tsdPtr->cwdPathPtr = Tcl_DuplicateObj(cwdPathPtr);
-    	    Tcl_IncrRefCount(tsdPtr->cwdPathPtr);
-        }
+	if (cwdPathPtr == NULL) {
+	    tsdPtr->cwdPathPtr = NULL;
+	} else {
+	    tsdPtr->cwdPathPtr = Tcl_DuplicateObj(cwdPathPtr);
+	    Tcl_IncrRefCount(tsdPtr->cwdPathPtr);
+	}
 	tsdPtr->cwdPathEpoch = cwdPathEpoch;
     } else if (tsdPtr->cwdPathEpoch != cwdPathEpoch) { 
-        Tcl_DecrRefCount(tsdPtr->cwdPathPtr);
-        if (cwdPathPtr == NULL) {
-    	    tsdPtr->cwdPathPtr = NULL;
-        } else {
-    	    tsdPtr->cwdPathPtr = Tcl_DuplicateObj(cwdPathPtr);
-    	    Tcl_IncrRefCount(tsdPtr->cwdPathPtr);
-        }
+	Tcl_DecrRefCount(tsdPtr->cwdPathPtr);
+	if (cwdPathPtr == NULL) {
+	    tsdPtr->cwdPathPtr = NULL;
+	} else {
+	    tsdPtr->cwdPathPtr = Tcl_DuplicateObj(cwdPathPtr);
+	    Tcl_IncrRefCount(tsdPtr->cwdPathPtr);
+	}
     }
     Tcl_MutexUnlock(&cwdMutex);
 
+    if (tsdPtr->initialized == 0) {
+	Tcl_CreateThreadExitHandler(FsThrExitProc, (ClientData)tsdPtr);
+	tsdPtr->initialized = 1;
+    }
     return (tsdPtr->cwdPathPtr == objPtr); 
 }
+#ifdef TCL_THREADS
 
-static FilesystemRecord* 
-FsGetIterator(void) {
-    Tcl_MutexLock(&filesystemMutex);
-    filesystemIteratorsInProgress++;
-    Tcl_MutexUnlock(&filesystemMutex);
-    /* Now we know the list of filesystems cannot be modified */
-    return filesystemList;
+static void
+FsRecacheFilesystemList(void)
+{
+    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+    FilesystemRecord *fsRecPtr, *tmpFsRecPtr;
+
+    /* Trash the current cache */
+    fsRecPtr = tsdPtr->filesystemList;
+    while (fsRecPtr != NULL) {
+	tmpFsRecPtr = fsRecPtr;
+	if (--fsRecPtr->fileRefCount <= 0) {
+	    ckfree((char *)fsRecPtr);
+	}
+	fsRecPtr = tmpFsRecPtr->nextPtr;
+    }
+    tsdPtr->filesystemList = NULL;
+
+    /*
+     * Code below operates on shared data. We
+     * are already called under mutex lock so   
+     * we can safely proceede.
+     */
+
+    /* Locate tail of the global filesystem list */
+    fsRecPtr = filesystemList;
+    while (fsRecPtr != NULL) {
+	tmpFsRecPtr = fsRecPtr;
+	fsRecPtr = fsRecPtr->nextPtr;
+    }
+    
+    /* Refill the cache honouring the order */
+    fsRecPtr = tmpFsRecPtr;
+    while (fsRecPtr != NULL) {
+	tmpFsRecPtr = (FilesystemRecord *)ckalloc(sizeof(FilesystemRecord));
+	*tmpFsRecPtr = *fsRecPtr;
+	tmpFsRecPtr->nextPtr = tsdPtr->filesystemList;
+	tmpFsRecPtr->prevPtr = NULL;
+	if (tsdPtr->filesystemList) {
+	    tsdPtr->filesystemList->prevPtr = tmpFsRecPtr;
+	}
+	tsdPtr->filesystemList = tmpFsRecPtr;
+        fsRecPtr = fsRecPtr->prevPtr;
+    }
+
+    /* Make sure the above gets released on thread exit */
+    if (tsdPtr->initialized == 0) {
+	Tcl_CreateThreadExitHandler(FsThrExitProc, (ClientData)tsdPtr);
+	tsdPtr->initialized = 1;
+    }
 }
+#endif
 
-static void 
-FsReleaseIterator(void) {
+static FilesystemRecord *
+FsGetFirstFilesystem(void) {
+    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+    FilesystemRecord *fsRecPtr;
+#ifndef TCL_THREADS
+    tsdPtr->filesystemEpoch = theFilesystemEpoch;
+    fsRecPtr = filesystemList;
+#else
     Tcl_MutexLock(&filesystemMutex);
-    filesystemIteratorsInProgress--;
-    if (filesystemIteratorsInProgress == 0) {
-        /* Notify any waiting threads that things are ok now */
-	if (filesystemWantToModify > 0) {
-	    Tcl_ConditionNotify(&filesystemOkToModify);
-	}
+    if (tsdPtr->filesystemList == NULL
+	    || (tsdPtr->filesystemEpoch != theFilesystemEpoch)) {
+ 	FsRecacheFilesystemList();
+	tsdPtr->filesystemEpoch = theFilesystemEpoch;
     }
     Tcl_MutexUnlock(&filesystemMutex);
+    fsRecPtr = tsdPtr->filesystemList;
+#endif
+    return fsRecPtr;
 }
 
 static void
@@ -611,7 +668,7 @@
     if (cwdObj == NULL) {
 	cwdPathPtr = NULL;
     } else {
-	/* This must be stored as string obj! */
+	/* This MUST be stored as string object! */
 	cwdPathPtr = Tcl_NewStringObj(str, len); 
     	Tcl_IncrRefCount(cwdPathPtr);
     }
@@ -653,6 +710,8 @@
 void
 TclFinalizeFilesystem()
 {
+    FilesystemRecord *fsRecPtr, *tmpFsRecPtr;
+
     /* 
      * Assumption that only one thread is active now.  Otherwise
      * we would need to put various mutexes around this code.
@@ -668,27 +727,25 @@
      * Remove all filesystems, freeing any allocated memory
      * that is no longer needed
      */
-    while (filesystemList != NULL) {
-	FilesystemRecord *tmpFsRecPtr = filesystemList->nextPtr;
-	if (filesystemList->fileRefCount > 0) {
-	    /* 
-	     * This filesystem must have some path objects still
-	     * around which will be freed later (e.g. when unloading
-	     * any shared libraries).  If not, then someone is
-	     * causing us to leak memory.
-	     */
-	} else {
+
+    fsRecPtr = filesystemList;
+    while (fsRecPtr != NULL) {
+	tmpFsRecPtr = filesystemList->nextPtr;
+	if (fsRecPtr->fileRefCount <= 0) {
 	    /* The native filesystem is static, so we don't free it */
-	    if (filesystemList != &nativeFilesystemRecord) {
-		ckfree((char *)filesystemList);
+	    if (fsRecPtr != &nativeFilesystemRecord) {
+		ckfree((char *)fsRecPtr);
 	    }
 	}
-	filesystemList = tmpFsRecPtr;
+	fsRecPtr = tmpFsRecPtr;
     }
+    filesystemList = NULL;
+
     /*
      * Now filesystemList is NULL.  This means that any attempt
      * to use the filesystem is likely to fail.
      */
+
     statProcList = NULL;
     accessProcList = NULL;
     openFileChannelProcList = NULL;
@@ -717,17 +774,13 @@
 TclResetFilesystem()
 {
     filesystemList = &nativeFilesystemRecord;
+
     /* 
      * Note, at this point, I believe nativeFilesystemRecord ->
      * fileRefCount should equal 1 and if not, we should try to track
      * down the cause.
      */
     
-    filesystemIteratorsInProgress = 0;
-    filesystemWantToModify = 0;
-#ifdef TCL_THREADS
-    filesystemOkToModify = NULL;
-#endif
 #ifdef __WIN32__
     /* 
      * Cleans up the win32 API filesystem proc lookup table. This must
@@ -804,14 +857,14 @@
      * a very rare action, this is not a very important point.
      */
     Tcl_MutexLock(&filesystemMutex);
-    if (filesystemIteratorsInProgress) {
-	filesystemWantToModify++;
-	Tcl_ConditionWait(&filesystemOkToModify, &filesystemMutex, NULL);
-	filesystemWantToModify--;
-    }
 
     newFilesystemPtr->nextPtr = filesystemList;
+    newFilesystemPtr->prevPtr = NULL;
+    if (filesystemList) {
+	filesystemList->prevPtr = newFilesystemPtr;
+    }
     filesystemList = newFilesystemPtr;
+
     /* 
      * Increment the filesystem epoch counter, since existing paths
      * might conceivably now belong to different filesystems.
@@ -852,28 +905,26 @@
     Tcl_Filesystem  *fsPtr;   /* The filesystem record to remove. */
 {
     int retVal = TCL_ERROR;
-    FilesystemRecord *tmpFsRecPtr;
-    FilesystemRecord *prevFsRecPtr = NULL;
+    FilesystemRecord *fsRecPtr;
 
     Tcl_MutexLock(&filesystemMutex);
-    if (filesystemIteratorsInProgress) {
-	filesystemWantToModify++;
-	Tcl_ConditionWait(&filesystemOkToModify, &filesystemMutex, NULL);
-	filesystemWantToModify--;
-    }
-    tmpFsRecPtr = filesystemList;
+
     /*
      * Traverse the 'filesystemList' looking for the particular node
      * whose 'fsPtr' member matches 'fsPtr' and remove that one from
      * the list.  Ensure that the "default" node cannot be removed.
      */
 
-    while ((retVal == TCL_ERROR) && (tmpFsRecPtr != &nativeFilesystemRecord)) {
-	if (tmpFsRecPtr->fsPtr == fsPtr) {
-	    if (prevFsRecPtr == NULL) {
-		filesystemList = filesystemList->nextPtr;
+    fsRecPtr = filesystemList;
+    while ((retVal == TCL_ERROR) && (fsRecPtr != &nativeFilesystemRecord)) {
+	if (fsRecPtr->fsPtr == fsPtr) {
+	    if (fsRecPtr->prevPtr) {
+		fsRecPtr->prevPtr->nextPtr = fsRecPtr->nextPtr;
 	    } else {
-		prevFsRecPtr->nextPtr = tmpFsRecPtr->nextPtr;
+		filesystemList = fsRecPtr->nextPtr;
+	    }
+	    if (fsRecPtr->nextPtr) {
+		fsRecPtr->nextPtr->prevPtr = fsRecPtr->prevPtr;
 	    }
 	    /* 
 	     * Increment the filesystem epoch counter, since existing
@@ -885,15 +936,14 @@
 	     */
 	    theFilesystemEpoch++;
 	    
-	    tmpFsRecPtr->fileRefCount--;
-	    if (tmpFsRecPtr->fileRefCount <= 0) {
-	        ckfree((char *)tmpFsRecPtr);
+	    fsRecPtr->fileRefCount--;
+	    if (fsRecPtr->fileRefCount <= 0) {
+	        ckfree((char *)fsRecPtr);
 	    }
 
 	    retVal = TCL_OK;
 	} else {
-	    prevFsRecPtr = tmpFsRecPtr;
-	    tmpFsRecPtr = tmpFsRecPtr->nextPtr;
+	    fsRecPtr = fsRecPtr->nextPtr;
 	}
     }
 
@@ -1119,24 +1169,22 @@
     Tcl_Filesystem  *fsPtr;   /* The filesystem record to query. */
 {
     ClientData retVal = NULL;
-    FilesystemRecord *tmpFsRecPtr;
+    FilesystemRecord *fsRecPtr = FsGetFirstFilesystem();
 
-    tmpFsRecPtr = FsGetIterator();
     /*
      * Traverse the 'filesystemList' looking for the particular node
      * whose 'fsPtr' member matches 'fsPtr' and remove that one from
      * the list.  Ensure that the "default" node cannot be removed.
      */
 
-    while ((retVal == NULL) && (tmpFsRecPtr != NULL)) {
-	if (tmpFsRecPtr->fsPtr == fsPtr) {
-	    retVal = tmpFsRecPtr->clientData;
+    while ((retVal == NULL) && (fsRecPtr != NULL)) {
+	if (fsRecPtr->fsPtr == fsPtr) {
+	    retVal = fsRecPtr->clientData;
 	}
-	tmpFsRecPtr = tmpFsRecPtr->nextPtr;
+	fsRecPtr = fsRecPtr->nextPtr;
     }
 
-    FsReleaseIterator();
-    return (retVal);
+    return retVal;
 }
 
 /*
@@ -1299,7 +1347,7 @@
     int startAt;
     ClientData *clientDataPtr;
 {
-    FilesystemRecord *fsRecPtr;
+    FilesystemRecord *fsRecPtr, *firstFsRecPtr;
     /* Ignore this variable */
     (void)clientDataPtr;
     
@@ -1310,7 +1358,9 @@
      * is always a native filesystem (i.e. '/' on unix is native).
      */
 
-    fsRecPtr = FsGetIterator();
+    firstFsRecPtr = FsGetFirstFilesystem();
+
+    fsRecPtr = firstFsRecPtr;
     while (fsRecPtr != NULL) {
         if (fsRecPtr == &nativeFilesystemRecord) {
 	    Tcl_FSNormalizePathProc *proc = fsRecPtr->fsPtr->normalizePathProc;
@@ -1321,9 +1371,8 @@
         }
 	fsRecPtr = fsRecPtr->nextPtr;
     }
-    FsReleaseIterator();
     
-    fsRecPtr = FsGetIterator();
+    fsRecPtr = firstFsRecPtr; 
     while (fsRecPtr != NULL) {
 	/* Skip the native system next time through */
 	if (fsRecPtr != &nativeFilesystemRecord) {
@@ -1341,9 +1390,8 @@
 	}
 	fsRecPtr = fsRecPtr->nextPtr;
     }
-    FsReleaseIterator();
 
-    return (startAt);
+    return startAt;
 }
 
 /*
@@ -2323,7 +2371,7 @@
 	 * succeeded.
 	 */
 
-	fsRecPtr = FsGetIterator();
+	fsRecPtr = FsGetFirstFilesystem();
 	while ((retVal == NULL) && (fsRecPtr != NULL)) {
 	    Tcl_FSGetCwdProc *proc = fsRecPtr->fsPtr->getCwdProc;
 	    if (proc != NULL) {
@@ -2331,7 +2379,6 @@
 	    }
 	    fsRecPtr = fsRecPtr->nextPtr;
 	}
-	FsReleaseIterator();
 	/* 
 	 * Now the 'cwd' may NOT be normalized, at least on some
 	 * platforms.  For the sake of efficiency, we want a completely
@@ -2345,8 +2392,7 @@
 	    if (norm != NULL) {
 		/* 
 		 * We found a cwd, which is now in our global storage.
-		 * We must make a copy.  Norm already has a refCount of
-		 * 1.
+		 * We must make a copy. Norm already has a refCount of 1.
 		 * 
 		 * Threading issue: note that multiple threads at system
 		 * startup could in principle call this procedure 
@@ -2953,7 +2999,7 @@
      * a list of all drives from all filesystems.
      */
 
-    fsRecPtr = FsGetIterator();
+    fsRecPtr = FsGetFirstFilesystem();
     while (fsRecPtr != NULL) {
 	Tcl_FSListVolumesProc *proc = fsRecPtr->fsPtr->listVolumesProc;
 	if (proc != NULL) {
@@ -2965,7 +3011,6 @@
 	}
 	fsRecPtr = fsRecPtr->nextPtr;
     }
-    FsReleaseIterator();
     
     return resultPtr;
 }
@@ -3069,22 +3114,20 @@
 
 /* Simple helper function */
 Tcl_Obj* 
-TclFSInternalToNormalized(fromFilesystem, clientData, fsRecPtrPtr, epochPtr)
+TclFSInternalToNormalized(fromFilesystem, clientData, fsRecPtrPtr)
     Tcl_Filesystem *fromFilesystem;
     ClientData clientData;
     FilesystemRecord **fsRecPtrPtr;
-    int *epochPtr;
 {
-    FilesystemRecord *fsRecPtr = FsGetIterator();
+    FilesystemRecord *fsRecPtr = FsGetFirstFilesystem();
+
     while (fsRecPtr != NULL) {
 	if (fsRecPtr->fsPtr == fromFilesystem) {
-	    *epochPtr = theFilesystemEpoch;
 	    *fsRecPtrPtr = fsRecPtr;
 	    break;
 	}
 	fsRecPtr = fsRecPtr->nextPtr;
     }
-    FsReleaseIterator();
     
     if ((fsRecPtr != NULL) 
       && (fromFilesystem->internalToNormalizedProc != NULL)) {
@@ -3134,7 +3177,7 @@
      * matches).
      */
 
-    fsRecPtr = FsGetIterator();
+    fsRecPtr = FsGetFirstFilesystem();
     while (fsRecPtr != NULL) {
 	Tcl_FSListVolumesProc *proc = fsRecPtr->fsPtr->listVolumesProc;
 	/* 
@@ -3208,7 +3251,6 @@
 	}
 	fsRecPtr = fsRecPtr->nextPtr;
     }
-    FsReleaseIterator();
     
     if (type != TCL_PATH_ABSOLUTE) {
 	type = TclpGetNativePathType(pathObjPtr, driveNameLengthPtr, 
@@ -3588,8 +3630,7 @@
      * Check if the filesystem has changed in some way since
      * this object's internal representation was calculated.
      */
-    if (TclFSEnsureEpochOk(pathObjPtr, theFilesystemEpoch, 
-			   &retVal) != TCL_OK) {
+    if (TclFSEnsureEpochOk(pathObjPtr, &retVal) != TCL_OK) {
 	return NULL;
     }
 
@@ -3599,7 +3640,7 @@
      * succeeded.
      */
 
-    fsRecPtr = FsGetIterator();
+    fsRecPtr = FsGetFirstFilesystem();
     while ((retVal == NULL) && (fsRecPtr != NULL)) {
 	Tcl_FSPathInFilesystemProc *proc = fsRecPtr->fsPtr->pathInFilesystemProc;
 	if (proc != NULL) {
@@ -3610,14 +3651,12 @@
 		 * We assume the type of pathObjPtr hasn't been changed 
 		 * by the above call to the pathInFilesystemProc.
 		 */
-		TclFSSetPathDetails(pathObjPtr, fsRecPtr, clientData, 
-			       theFilesystemEpoch);
+		TclFSSetPathDetails(pathObjPtr, fsRecPtr, clientData);
 		retVal = fsRecPtr->fsPtr;
 	    }
 	}
 	fsRecPtr = fsRecPtr->nextPtr;
     }
-    FsReleaseIterator();
 
     return retVal;
 }
@@ -3995,7 +4034,7 @@
 	}
     }
 
-    return (retVal);
+    return retVal;
 }
 
 /*
@@ -4051,7 +4090,8 @@
     }
 
     Tcl_MutexUnlock(&obsoleteFsHookMutex);
-    return (retVal);
+
+    return retVal;
 }
 
 /*
@@ -4099,7 +4139,7 @@
 	}
     }
 
-    return (retVal);
+    return retVal;
 }
 
 /*
@@ -4155,7 +4195,7 @@
     }
     Tcl_MutexUnlock(&obsoleteFsHookMutex);
 
-    return (retVal);
+    return retVal;
 }
 
 /*
@@ -4204,7 +4244,7 @@
 	}
     }
 
-    return (retVal);
+    return retVal;
 }
 
 /*
@@ -4262,7 +4302,7 @@
     }
     Tcl_MutexUnlock(&obsoleteFsHookMutex);
 
-    return (retVal);
+    return retVal;
 }
 #endif /* USE_OBSOLETE_FS_HOOKS */
 
@@ -4631,6 +4671,8 @@
     Tcl_Obj *objPtr;		/* Object to convert to a valid, current
 				 * path type. */
 {
+    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+
     /* 
      * While it is bad practice to examine an object's type directly,
      * this is actually the best thing to do here.  The reason is that
@@ -4642,7 +4684,7 @@
      */
     if (objPtr->typePtr == &tclFsPathType) {
 	FsPath *fsPathPtr = (FsPath*) PATHOBJ(objPtr);
-	if (fsPathPtr->filesystemEpoch != theFilesystemEpoch) {
+	if (fsPathPtr->filesystemEpoch != tsdPtr->filesystemEpoch) {
 	    if (objPtr->bytes == NULL) {
 		UpdateStringOfFsPath(objPtr);
 	    }
@@ -4734,6 +4776,7 @@
 {
     FsPath *fsPathPtr;
     Tcl_Obj *objPtr;
+    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
     
     objPtr = Tcl_NewObj();
     fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));
@@ -4758,13 +4801,14 @@
     Tcl_IncrRefCount(dirPtr);
     fsPathPtr->nativePathPtr = NULL;
     fsPathPtr->fsRecPtr = NULL;
-    fsPathPtr->filesystemEpoch = theFilesystemEpoch;
+    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;
 
     PATHOBJ(objPtr) = (VOID *) fsPathPtr;
     PATHFLAGS(objPtr) = TCLPATH_RELATIVE | TCLPATH_APPENDED;
     objPtr->typePtr = &tclFsPathType;
     objPtr->bytes = NULL;
     objPtr->length = 0;
+
     return objPtr;
 }
 
@@ -4793,9 +4837,10 @@
 {
     int cwdLen, len;
     CONST char *tempStr;
+    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
     
     if (objPtr->typePtr == &tclFsPathType) {
-	FsPath* fsPathPtr = (FsPath*) PATHOBJ(objPtr);
+	FsPath *fsPathPtr = (FsPath*) PATHOBJ(objPtr);
 	if (PATHFLAGS(objPtr) != 0 
 		&& fsPathPtr->cwdPtr == cwdPtr) {
 	    objPtr = fsPathPtr->normPathPtr;
@@ -4826,7 +4871,7 @@
 	    Tcl_IncrRefCount(cwdPtr);
 	    fsPathPtr->nativePathPtr = NULL;
 	    fsPathPtr->fsRecPtr = NULL;
-	    fsPathPtr->filesystemEpoch = theFilesystemEpoch;
+	    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;
 
 	    PATHOBJ(objPtr) = (VOID *) fsPathPtr;
 	    PATHFLAGS(objPtr) = 0;
@@ -4873,6 +4918,7 @@
 	    break;
     }
     tempStr = Tcl_GetStringFromObj(objPtr, &len);
+
     return Tcl_NewStringObj(tempStr + cwdLen, len - cwdLen);
 }
 
@@ -4901,6 +4947,7 @@
 				 * else NULL. */
 {
     FsPath *fsPathPtr;
+    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
 
     if (objPtr->typePtr == &tclFsPathType) {
 	return TCL_OK;
@@ -4931,7 +4978,7 @@
     fsPathPtr->cwdPtr = NULL;
     fsPathPtr->nativePathPtr = nativeRep;
     fsPathPtr->fsRecPtr = NULL;
-    fsPathPtr->filesystemEpoch = theFilesystemEpoch;
+    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;
 
     PATHOBJ(objPtr) = (VOID *) fsPathPtr;
     PATHFLAGS(objPtr) = 0;
@@ -4975,11 +5022,9 @@
     FsPath *fsPathPtr;
 
     FilesystemRecord *fsFromPtr;
-    int epoch;
+    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
     
-    objPtr = TclFSInternalToNormalized(fromFilesystem, clientData, 
-				       &fsFromPtr, &epoch);
-
+    objPtr = TclFSInternalToNormalized(fromFilesystem, clientData, &fsFromPtr);
     if (objPtr == NULL) {
 	return NULL;
     }
@@ -5001,19 +5046,20 @@
     }
     
     fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));
+
     fsPathPtr->translatedPathPtr = NULL;
     /* Circular reference, by design */
     fsPathPtr->normPathPtr = objPtr;
     fsPathPtr->cwdPtr = NULL;
     fsPathPtr->nativePathPtr = clientData;
     fsPathPtr->fsRecPtr = fsFromPtr;
-    /* We must increase the refCount for this filesystem. */
     fsPathPtr->fsRecPtr->fileRefCount++;
-    fsPathPtr->filesystemEpoch = epoch;
+    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;
 
     PATHOBJ(objPtr) = (VOID *) fsPathPtr;
     PATHFLAGS(objPtr) = 0;
     objPtr->typePtr = &tclFsPathType;
+
     return objPtr;
 }
 
@@ -5042,7 +5088,9 @@
     Tcl_Interp *interp;
     Tcl_Obj* pathPtr;
 {
-    register FsPath* srcFsPathPtr;
+    Tcl_Obj *retObj = NULL;
+    FsPath *srcFsPathPtr;
+
     if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) {
 	return NULL;
     }
@@ -5057,11 +5105,13 @@
 	 * object's string, translatedPath and normalizedPath
 	 * are all identical.
 	 */
-	return srcFsPathPtr->normPathPtr;
+	retObj = srcFsPathPtr->normPathPtr;
     } else {
 	/* It is an ordinary path object */
-	return srcFsPathPtr->translatedPathPtr;
+	retObj = srcFsPathPtr->translatedPathPtr;
     }
+
+    return retObj;
 }
 
 /*
@@ -5089,11 +5139,12 @@
     Tcl_Obj* pathPtr;
 {
     Tcl_Obj *transPtr = Tcl_FSGetTranslatedPath(interp, pathPtr);
-    if (transPtr == NULL) {
-	return NULL;
-    } else {
+
+    if (transPtr != NULL) {
 	return Tcl_GetString(transPtr);
     }
+
+    return NULL;
 }
 
 /*
@@ -5120,7 +5171,8 @@
     Tcl_Interp *interp;
     Tcl_Obj* pathObjPtr;
 {
-    register FsPath* fsPathPtr;
+    FsPath *fsPathPtr;
+
     if (Tcl_FSConvertToPathType(interp, pathObjPtr) != TCL_OK) {
 	return NULL;
     }
@@ -5192,7 +5244,7 @@
 	/* Now we need to construct the new path object */
 	
 	if (pathType == TCL_PATH_RELATIVE) {
-	    register FsPath* origDirFsPathPtr;
+	    FsPath* origDirFsPathPtr;
 	    Tcl_Obj *origDir = fsPathPtr->cwdPtr;
 	    origDirFsPathPtr = (FsPath*) PATHOBJ(origDir);
 	    
@@ -5334,6 +5386,7 @@
 	    fsPathPtr->cwdPtr = useThisCwd;
 	}
     }
+
     return fsPathPtr->normPathPtr;
 }
 
@@ -5364,7 +5417,7 @@
     Tcl_Obj* pathObjPtr;
     Tcl_Filesystem *fsPtr;
 {
-    register FsPath* srcFsPathPtr;
+    FsPath *srcFsPathPtr;
     
     if (Tcl_FSConvertToPathType(NULL, pathObjPtr) != TCL_OK) {
 	return NULL;
@@ -5434,6 +5487,7 @@
 	}
 	srcFsPathPtr->nativePathPtr = (*proc)(pathObjPtr);
     }
+
     return srcFsPathPtr->nativePathPtr;
 }
 
@@ -5457,12 +5511,12 @@
  */
 
 int 
-TclFSEnsureEpochOk(pathObjPtr, theEpoch, fsPtrPtr)
+TclFSEnsureEpochOk(pathObjPtr, fsPtrPtr)
     Tcl_Obj* pathObjPtr;
-    int theEpoch;
     Tcl_Filesystem **fsPtrPtr;
 {
-    FsPath* srcFsPathPtr;
+    FsPath *srcFsPathPtr;
+    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
 
     /* 
      * SHOULD BE ABLE TO IMPROVE EFFICIENCY HERE.
@@ -5478,7 +5532,7 @@
      * Check if the filesystem has changed in some way since
      * this object's internal representation was calculated.
      */
-    if (srcFsPathPtr->filesystemEpoch != theEpoch) {
+    if (srcFsPathPtr->filesystemEpoch != tsdPtr->filesystemEpoch) {
 	/* 
 	 * We have to discard the stale representation and 
 	 * recalculate it 
@@ -5497,23 +5551,24 @@
     if (srcFsPathPtr->fsRecPtr != NULL) {
 	*fsPtrPtr = srcFsPathPtr->fsRecPtr->fsPtr;
     }
+
     return TCL_OK;
 }
 
 void 
-TclFSSetPathDetails(pathObjPtr, fsRecPtr, clientData, theEpoch) 
+TclFSSetPathDetails(pathObjPtr, fsRecPtr, clientData) 
     Tcl_Obj *pathObjPtr;
     FilesystemRecord *fsRecPtr;
     ClientData clientData;
-    int theEpoch;
 {
+    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
     /* We assume pathObjPtr is already of the correct type */
-    FsPath* srcFsPathPtr;
+    FsPath *srcFsPathPtr;
     
     srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr);
     srcFsPathPtr->fsRecPtr = fsRecPtr;
     srcFsPathPtr->nativePathPtr = clientData;
-    srcFsPathPtr->filesystemEpoch = theEpoch;
+    srcFsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;
     fsRecPtr->fileRefCount++;
 }
 
@@ -5572,6 +5627,7 @@
 	    return 1;
 	}
     }
+
     return 0;
 }
 
@@ -5605,6 +5661,7 @@
     FsPath *fsPathPtr;
     Tcl_Obj *transPtr;
     char *name;
+    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
     
     if (objPtr->typePtr == &tclFsPathType) {
 	return TCL_OK;
@@ -5722,13 +5779,14 @@
      */
     
     fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));
+
     fsPathPtr->translatedPathPtr = transPtr;
     Tcl_IncrRefCount(fsPathPtr->translatedPathPtr);
     fsPathPtr->normPathPtr = NULL;
     fsPathPtr->cwdPtr = NULL;
     fsPathPtr->nativePathPtr = NULL;
     fsPathPtr->fsRecPtr = NULL;
-    fsPathPtr->filesystemEpoch = theFilesystemEpoch;
+    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;
 
     /*
      * Free old representation before installing our new one.
@@ -5747,7 +5805,7 @@
 FreeFsPathInternalRep(pathObjPtr)
     Tcl_Obj *pathObjPtr;	/* Path object with internal rep to free. */
 {
-    register FsPath* fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr);
+    FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr);
 
     if (fsPathPtr->translatedPathPtr != NULL) {
 	if (fsPathPtr->translatedPathPtr != pathObjPtr) {
@@ -5775,7 +5833,7 @@
     if (fsPathPtr->fsRecPtr != NULL) {
 	fsPathPtr->fsRecPtr->fileRefCount--;
 	if (fsPathPtr->fsRecPtr->fileRefCount <= 0) {
-	    /* It has been unregistered already */
+	    /* It has been unregistered already, so simply free it */
 	    ckfree((char *)fsPathPtr->fsRecPtr);
 	}
     }
@@ -5789,9 +5847,9 @@
     Tcl_Obj *srcPtr;		/* Path obj with internal rep to copy. */
     Tcl_Obj *copyPtr;		/* Path obj with internal rep to set. */
 {
-    register FsPath* srcFsPathPtr = (FsPath*) PATHOBJ(srcPtr);
-    register FsPath* copyFsPathPtr = 
-      (FsPath*) ckalloc((unsigned)sizeof(FsPath));
+    FsPath *srcFsPathPtr = (FsPath*) PATHOBJ(srcPtr);
+    FsPath *copyFsPathPtr = (FsPath*) ckalloc((unsigned)sizeof(FsPath));
+      
     Tcl_FSDupInternalRepProc *dupProc;
     
     PATHOBJ(copyPtr) = (VOID *) copyFsPathPtr;
@@ -5864,7 +5922,7 @@
 UpdateStringOfFsPath(objPtr)
     register Tcl_Obj *objPtr;	/* path obj with string rep to update. */
 {
-    register FsPath* fsPathPtr = (FsPath*) PATHOBJ(objPtr);
+    FsPath *fsPathPtr = (FsPath*) PATHOBJ(objPtr);
     CONST char *cwdStr;
     int cwdLen;
     Tcl_Obj *copy;