summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclFileSystem.h1
-rw-r--r--generic/tclIOUtil.c113
-rw-r--r--generic/tclPathObj.c21
3 files changed, 98 insertions, 37 deletions
diff --git a/generic/tclFileSystem.h b/generic/tclFileSystem.h
index 3dfc1de..778c9ac 100644
--- a/generic/tclFileSystem.h
+++ b/generic/tclFileSystem.h
@@ -52,6 +52,7 @@ typedef struct ThreadSpecificData {
Tcl_Obj *cwdPathPtr;
ClientData cwdClientData;
FilesystemRecord *filesystemList;
+ int claims;
} ThreadSpecificData;
/*
diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c
index 3bdcca3..117fab3 100644
--- a/generic/tclIOUtil.c
+++ b/generic/tclIOUtil.c
@@ -39,9 +39,10 @@ static void FsAddMountsToGlobResult(Tcl_Obj *resultPtr,
Tcl_GlobTypeData *types);
static void FsUpdateCwd(Tcl_Obj *cwdObj, ClientData clientData);
-#ifdef TCL_THREADS
static void FsRecacheFilesystemList(void);
-#endif
+static void Claim(void);
+static void Disclaim(void);
+
/*
* These form part of the native filesystem support. They are needed here
@@ -410,7 +411,7 @@ static FilesystemRecord nativeFilesystemRecord = {
* trigger cache cleanup in all threads.
*/
-static int theFilesystemEpoch = 0;
+static int theFilesystemEpoch = 1;
/*
* Stores the linked list of filesystems. A 1:1 copy of this list is also
@@ -583,34 +584,41 @@ TclFSCwdPointerEquals(
}
}
-#ifdef TCL_THREADS
static void
FsRecacheFilesystemList(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
- FilesystemRecord *fsRecPtr, *tmpFsRecPtr = NULL;
+ FilesystemRecord *fsRecPtr, *tmpFsRecPtr = NULL, *chain = NULL;
/*
* Trash the current cache.
*/
fsRecPtr = tsdPtr->filesystemList;
- while (fsRecPtr != NULL) {
- tmpFsRecPtr = fsRecPtr->nextPtr;
- if (--fsRecPtr->fileRefCount <= 0) {
- ckfree((char *)fsRecPtr);
+ if (tsdPtr->claims <= 0) {
+ while (fsRecPtr != NULL) {
+ tmpFsRecPtr = fsRecPtr->nextPtr;
+ if (--fsRecPtr->fileRefCount <= 0) {
+ ckfree((char *)fsRecPtr);
+ }
+ fsRecPtr = tmpFsRecPtr;
}
- fsRecPtr = tmpFsRecPtr;
+ } else {
+ chain = fsRecPtr;
+ while (fsRecPtr->nextPtr != NULL) {
+ fsRecPtr->prevPtr = fsRecPtr->nextPtr;
+ fsRecPtr->nextPtr = NULL;
+ fsRecPtr = fsRecPtr->prevPtr;
+ }
+ fsRecPtr->prevPtr = fsRecPtr;
}
tsdPtr->filesystemList = NULL;
/*
- * Code below operates on shared data. We are already called under mutex
- * lock so we can safely proceed.
- *
* Locate tail of the global filesystem list.
*/
+ Tcl_MutexLock(&filesystemMutex);
fsRecPtr = filesystemList;
while (fsRecPtr != NULL) {
tmpFsRecPtr = fsRecPtr;
@@ -626,13 +634,13 @@ FsRecacheFilesystemList(void)
tmpFsRecPtr = (FilesystemRecord *) ckalloc(sizeof(FilesystemRecord));
*tmpFsRecPtr = *fsRecPtr;
tmpFsRecPtr->nextPtr = tsdPtr->filesystemList;
- tmpFsRecPtr->prevPtr = NULL;
- if (tsdPtr->filesystemList) {
- tsdPtr->filesystemList->prevPtr = tmpFsRecPtr;
- }
+ tmpFsRecPtr->prevPtr = chain;
+ chain = NULL;
tsdPtr->filesystemList = tmpFsRecPtr;
fsRecPtr = fsRecPtr->prevPtr;
}
+ tsdPtr->filesystemEpoch = theFilesystemEpoch;
+ Tcl_MutexUnlock(&filesystemMutex);
/*
* Make sure the above gets released on thread exit.
@@ -643,27 +651,16 @@ FsRecacheFilesystemList(void)
tsdPtr->initialized = 1;
}
}
-#endif /* TCL_THREADS */
static FilesystemRecord *
FsGetFirstFilesystem(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
- FilesystemRecord *fsRecPtr;
-#ifndef TCL_THREADS
- tsdPtr->filesystemEpoch = theFilesystemEpoch;
- fsRecPtr = filesystemList;
-#else
- Tcl_MutexLock(&filesystemMutex);
if (tsdPtr->filesystemList == NULL
|| (tsdPtr->filesystemEpoch != theFilesystemEpoch)) {
FsRecacheFilesystemList();
- tsdPtr->filesystemEpoch = theFilesystemEpoch;
}
- Tcl_MutexUnlock(&filesystemMutex);
- fsRecPtr = tsdPtr->filesystemList;
-#endif
- return fsRecPtr;
+ return tsdPtr->filesystemList;
}
/*
@@ -675,9 +672,48 @@ int
TclFSEpochOk(
int filesystemEpoch)
{
+ return (filesystemEpoch == 0 || filesystemEpoch == theFilesystemEpoch);
+}
+
+static void
+Claim()
+{
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
+
+ tsdPtr->claims++;
+}
+
+static void
+Disclaim()
+{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
- (void) FsGetFirstFilesystem();
- return (filesystemEpoch == tsdPtr->filesystemEpoch);
+ FilesystemRecord *fsRecPtr, *toRelease, *lastCurrent;
+
+ if (--tsdPtr->claims > 0) {
+ return;
+ }
+ fsRecPtr = tsdPtr->filesystemList;
+
+ /*
+ * Release all out of date FilesystemRecords.
+ * First skip the current list.
+ */
+ while (fsRecPtr->nextPtr != NULL) {
+ fsRecPtr = fsRecPtr->nextPtr;
+ }
+
+ /* Then release everything that comes after. */
+ lastCurrent = fsRecPtr;
+ toRelease = lastCurrent->prevPtr;
+ lastCurrent->prevPtr = NULL;
+ while (toRelease != NULL) {
+ fsRecPtr = (toRelease == toRelease->prevPtr) ? NULL
+ : toRelease->prevPtr;
+ if (--toRelease->fileRefCount <= 0) {
+ ckfree((char *)toRelease);
+ }
+ toRelease = fsRecPtr;
+ }
}
/*
@@ -798,6 +834,7 @@ TclFinalizeFilesystem(void)
}
fsRecPtr = tmpFsRecPtr;
}
+ theFilesystemEpoch++;
filesystemList = NULL;
/*
@@ -835,6 +872,7 @@ void
TclResetFilesystem(void)
{
filesystemList = &nativeFilesystemRecord;
+ theFilesystemEpoch++;
/*
* Note, at this point, I believe nativeFilesystemRecord -> fileRefCount
@@ -1422,6 +1460,7 @@ TclFSNormalizeToUniquePath(
firstFsRecPtr = FsGetFirstFilesystem();
+ Claim();
fsRecPtr = firstFsRecPtr;
while (fsRecPtr != NULL) {
if (fsRecPtr->fsPtr == &tclNativeFilesystem) {
@@ -1454,6 +1493,7 @@ TclFSNormalizeToUniquePath(
}
fsRecPtr = fsRecPtr->nextPtr;
}
+ Disclaim();
return startAt;
}
@@ -2648,6 +2688,7 @@ Tcl_FSGetCwd(
*/
fsRecPtr = FsGetFirstFilesystem();
+ Claim();
while ((retVal == NULL) && (fsRecPtr != NULL)) {
Tcl_FSGetCwdProc *proc = fsRecPtr->fsPtr->getCwdProc;
if (proc != NULL) {
@@ -2685,6 +2726,7 @@ Tcl_FSGetCwd(
}
Tcl_DecrRefCount(retVal);
retVal = NULL;
+ Disclaim();
goto cdDidNotChange;
} else if (interp != NULL) {
Tcl_AppendResult(interp,
@@ -2697,6 +2739,7 @@ Tcl_FSGetCwd(
}
fsRecPtr = fsRecPtr->nextPtr;
}
+ Disclaim();
/*
* Now the 'cwd' may NOT be normalized, at least on some platforms.
@@ -3642,6 +3685,7 @@ Tcl_FSListVolumes(void)
*/
fsRecPtr = FsGetFirstFilesystem();
+ Claim();
while (fsRecPtr != NULL) {
Tcl_FSListVolumesProc *proc = fsRecPtr->fsPtr->listVolumesProc;
if (proc != NULL) {
@@ -3653,6 +3697,7 @@ Tcl_FSListVolumes(void)
}
fsRecPtr = fsRecPtr->nextPtr;
}
+ Disclaim();
return resultPtr;
}
@@ -3692,6 +3737,7 @@ FsListMounts(
*/
fsRecPtr = FsGetFirstFilesystem();
+ Claim();
while (fsRecPtr != NULL) {
if (fsRecPtr->fsPtr != &tclNativeFilesystem) {
Tcl_FSMatchInDirectoryProc *proc =
@@ -3705,6 +3751,7 @@ FsListMounts(
}
fsRecPtr = fsRecPtr->nextPtr;
}
+ Disclaim();
return resultPtr;
}
@@ -3917,6 +3964,7 @@ TclFSNonnativePathType(
*/
fsRecPtr = FsGetFirstFilesystem();
+ Claim();
while (fsRecPtr != NULL) {
Tcl_FSListVolumesProc *proc = fsRecPtr->fsPtr->listVolumesProc;
@@ -3995,6 +4043,7 @@ TclFSNonnativePathType(
}
fsRecPtr = fsRecPtr->nextPtr;
}
+ Disclaim();
return type;
}
@@ -4389,6 +4438,7 @@ Tcl_FSGetFileSystemForPath(
*/
fsRecPtr = FsGetFirstFilesystem();
+ Claim();
if (TclFSEnsureEpochOk(pathPtr, &retVal) != TCL_OK) {
return NULL;
@@ -4417,6 +4467,7 @@ Tcl_FSGetFileSystemForPath(
}
fsRecPtr = fsRecPtr->nextPtr;
}
+ Disclaim();
return retVal;
}
diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c
index 7911dea..66cc617 100644
--- a/generic/tclPathObj.c
+++ b/generic/tclPathObj.c
@@ -563,8 +563,8 @@ TclPathPart(
if (pathPtr->typePtr == &tclFsPathType) {
FsPath *fsPathPtr = PATHOBJ(pathPtr);
- if (TclFSEpochOk(fsPathPtr->filesystemEpoch)
- && (PATHFLAGS(pathPtr) != 0)) {
+ if (/*TclFSEpochOk(fsPathPtr->filesystemEpoch)
+ && */(PATHFLAGS(pathPtr) != 0)) {
switch (portion) {
case TCL_PATH_DIRNAME: {
/*
@@ -1311,7 +1311,7 @@ TclNewFSPathObj(
Tcl_IncrRefCount(dirPtr);
fsPathPtr->nativePathPtr = NULL;
fsPathPtr->fsPtr = NULL;
- fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;
+ fsPathPtr->filesystemEpoch = 0;
SETPATHOBJ(pathPtr, fsPathPtr);
PATHFLAGS(pathPtr) = TCLPATH_APPENDED;
@@ -1417,7 +1417,6 @@ TclFSMakePathRelative(
{
int cwdLen, len;
const char *tempStr;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
if (pathPtr->typePtr == &tclFsPathType) {
FsPath *fsPathPtr = PATHOBJ(pathPtr);
@@ -1481,7 +1480,7 @@ TclFSMakePathRelative(
Tcl_IncrRefCount(cwdPtr);
fsPathPtr->nativePathPtr = NULL;
fsPathPtr->fsPtr = NULL;
- fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;
+ fsPathPtr->filesystemEpoch = 0;
SETPATHOBJ(pathPtr, fsPathPtr);
PATHFLAGS(pathPtr) = 0;
@@ -1591,6 +1590,7 @@ TclFSMakePathFromNormalized(
fsPathPtr->cwdPtr = NULL;
fsPathPtr->nativePathPtr = NULL;
fsPathPtr->fsPtr = NULL;
+ /* Remember the epoch under which we decided pathPtr was normalized */
fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;
SETPATHOBJ(pathPtr, fsPathPtr);
@@ -1727,6 +1727,12 @@ Tcl_FSGetTranslatedPath(
retObj = Tcl_FSJoinToPath(translatedCwdPtr, 1,
&(srcFsPathPtr->normPathPtr));
srcFsPathPtr->translatedPathPtr = retObj;
+ if (translatedCwdPtr->typePtr == &tclFsPathType) {
+ srcFsPathPtr->filesystemEpoch
+ = PATHOBJ(translatedCwdPtr)->filesystemEpoch;
+ } else {
+ srcFsPathPtr->filesystemEpoch = 0;
+ }
Tcl_IncrRefCount(retObj);
Tcl_DecrRefCount(translatedCwdPtr);
} else {
@@ -2527,12 +2533,15 @@ SetFsPathFromAny(
fsPathPtr->translatedPathPtr = transPtr;
if (transPtr != pathPtr) {
Tcl_IncrRefCount(fsPathPtr->translatedPathPtr);
+ /* Redo translation when $env(HOME) changes */
+ fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;
+ } else {
+ fsPathPtr->filesystemEpoch = 0;
}
fsPathPtr->normPathPtr = NULL;
fsPathPtr->cwdPtr = NULL;
fsPathPtr->nativePathPtr = NULL;
fsPathPtr->fsPtr = NULL;
- fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;
/*
* Free old representation before installing our new one.