diff options
-rw-r--r-- | generic/tclFileSystem.h | 1 | ||||
-rw-r--r-- | generic/tclIOUtil.c | 113 |
2 files changed, 84 insertions, 30 deletions
diff --git a/generic/tclFileSystem.h b/generic/tclFileSystem.h index d6e1546..e11ac16 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 e3c5816..0600a6c 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 @@ -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 == 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; } @@ -3823,6 +3870,7 @@ TclFSInternalToNormalized( { FilesystemRecord *fsRecPtr = FsGetFirstFilesystem(); + Claim(); while (fsRecPtr != NULL) { if (fsRecPtr->fsPtr == fromFilesystem) { *fsRecPtrPtr = fsRecPtr; @@ -3830,6 +3878,7 @@ TclFSInternalToNormalized( } fsRecPtr = fsRecPtr->nextPtr; } + Disclaim(); if ((fsRecPtr != NULL) && (fromFilesystem->internalToNormalizedProc != NULL)) { @@ -3942,6 +3991,7 @@ TclFSNonnativePathType( */ fsRecPtr = FsGetFirstFilesystem(); + Claim(); while (fsRecPtr != NULL) { Tcl_FSListVolumesProc *proc = fsRecPtr->fsPtr->listVolumesProc; @@ -4020,6 +4070,7 @@ TclFSNonnativePathType( } fsRecPtr = fsRecPtr->nextPtr; } + Disclaim(); return type; } @@ -4414,6 +4465,7 @@ Tcl_FSGetFileSystemForPath( */ fsRecPtr = FsGetFirstFilesystem(); + Claim(); if (TclFSEnsureEpochOk(pathPtr, &retVal) != TCL_OK) { return NULL; @@ -4442,6 +4494,7 @@ Tcl_FSGetFileSystemForPath( } fsRecPtr = fsRecPtr->nextPtr; } + Disclaim(); return retVal; } |