From 0359aa1dedfd9abdaef6487a9593f462ebe1265f Mon Sep 17 00:00:00 2001 From: vasiljevic Date: Sat, 23 Aug 2003 12:16:49 +0000 Subject: Applied changes from 8.4.4 regarding the Bug #753315 --- generic/tclFileSystem.h | 30 ++++- generic/tclIOUtil.c | 317 +++++++++++++++++++++++++----------------------- generic/tclPathObj.c | 99 +++++++++------ 3 files changed, 251 insertions(+), 195 deletions(-) diff --git a/generic/tclFileSystem.h b/generic/tclFileSystem.h index 966f221..7d74dc2 100644 --- a/generic/tclFileSystem.h +++ b/generic/tclFileSystem.h @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclFileSystem.h,v 1.2 2003/04/14 15:48:35 vincentdarley Exp $ + * RCS: @(#) $Id: tclFileSystem.h,v 1.3 2003/08/23 12:16:49 vasiljevic Exp $ */ /* @@ -31,8 +31,28 @@ typedef struct FilesystemRecord { 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; +/* + * 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; + /* * The internal TclFS API provides routines for handling and * manipulating paths efficiently, taking direct advantage of @@ -50,12 +70,11 @@ Tcl_Obj* TclFSMakePathRelative _ANSI_ARGS_((Tcl_Interp *interp, 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 )); Tcl_Obj* TclFSNormalizeAbsolutePath _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj *pathPtr, ClientData *clientDataPtr)); @@ -64,6 +83,7 @@ Tcl_Obj* TclFSNormalizeAbsolutePath _ANSI_ARGS_((Tcl_Interp* interp, */ extern Tcl_Filesystem tclNativeFilesystem; extern int theFilesystemEpoch; +extern Tcl_ThreadDataKey fsDataKey; /* * Private shared functions for use by tclIOUtil.c and tclPathObj.c diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c index edcad14..1999598 100644 --- a/generic/tclIOUtil.c +++ b/generic/tclIOUtil.c @@ -17,7 +17,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIOUtil.c,v 1.81 2003/05/13 22:59:49 hobbs Exp $ + * RCS: @(#) $Id: tclIOUtil.c,v 1.82 2003/08/23 12:16:49 vasiljevic Exp $ */ #include "tclInt.h" @@ -35,10 +35,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 @@ -387,58 +390,30 @@ static FilesystemRecord nativeFilesystemRecord = { }; /* - * 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. - */ -typedef struct ThreadSpecificData { - int initialized; - int cwdPathEpoch; - Tcl_Obj *cwdPathPtr; -} ThreadSpecificData; - -Tcl_ThreadDataKey dataKey; +Tcl_ThreadDataKey fsDataKey; /* * Declare fallback support function and @@ -469,23 +444,35 @@ FsThrExitProc(cd) 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 TclFSCwdPointerEquals(objPtr) Tcl_Obj* objPtr; { - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); Tcl_MutexLock(&cwdMutex); - if (tsdPtr->initialized == 0) { - Tcl_CreateThreadExitHandler(FsThrExitProc, (ClientData)tsdPtr); - tsdPtr->initialized = 1; - } - if (tsdPtr->cwdPathPtr == NULL) { + if (tsdPtr->cwdPathPtr == NULL + || tsdPtr->cwdPathEpoch != cwdPathEpoch) { + if (tsdPtr->cwdPathPtr) { + Tcl_DecrRefCount(tsdPtr->cwdPathPtr); + } if (cwdPathPtr == NULL) { tsdPtr->cwdPathPtr = NULL; } else { @@ -493,40 +480,88 @@ TclFSCwdPointerEquals(objPtr) 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_MutexUnlock(&cwdMutex); + if (tsdPtr->initialized == 0) { + Tcl_CreateThreadExitHandler(FsThrExitProc, (ClientData)tsdPtr); + tsdPtr->initialized = 1; + } + return (tsdPtr->cwdPathPtr == objPtr); } -static FilesystemRecord* -FsGetIterator(void) { - Tcl_MutexLock(&filesystemMutex); - filesystemIteratorsInProgress++; - Tcl_MutexUnlock(&filesystemMutex); - /* Now we know the list of filesystems cannot be modified */ - return filesystemList; +#ifdef TCL_THREADS +static void +FsRecacheFilesystemList(void) +{ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); + FilesystemRecord *fsRecPtr, *tmpFsRecPtr; + + /* Trash the current cache */ + fsRecPtr = tsdPtr->filesystemList; + while (fsRecPtr != NULL) { + tmpFsRecPtr = fsRecPtr->nextPtr; + if (--fsRecPtr->fileRefCount <= 0) { + ckfree((char *)fsRecPtr); + } + fsRecPtr = tmpFsRecPtr; + } + 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 /* TCL_THREADS */ -static void -FsReleaseIterator(void) { +static FilesystemRecord * +FsGetFirstFilesystem(void) { + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); + 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 @@ -535,7 +570,7 @@ FsUpdateCwd(cwdObj) { int len; char *str = NULL; - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); if (cwdObj != NULL) { str = Tcl_GetStringFromObj(cwdObj, &len); @@ -590,6 +625,8 @@ FsUpdateCwd(cwdObj) void TclFinalizeFilesystem() { + FilesystemRecord *fsRecPtr, *tmpFsRecPtr; + /* * Assumption that only one thread is active now. Otherwise * we would need to put various mutexes around this code. @@ -605,27 +642,25 @@ TclFinalizeFilesystem() * 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 { - /* The native filesystem is static, so we don't free it */ - if (filesystemList != &nativeFilesystemRecord) { - ckfree((char *)filesystemList); - } - } - filesystemList = tmpFsRecPtr; + + fsRecPtr = filesystemList; + while (fsRecPtr != NULL) { + tmpFsRecPtr = filesystemList->nextPtr; + if (fsRecPtr->fileRefCount <= 0) { + /* The native filesystem is static, so we don't free it */ + if (fsRecPtr != &nativeFilesystemRecord) { + ckfree((char *)fsRecPtr); + } + } + 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; @@ -660,11 +695,6 @@ TclResetFilesystem() * 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 @@ -741,14 +771,14 @@ Tcl_FSRegister(clientData, fsPtr) * 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. @@ -789,28 +819,26 @@ Tcl_FSUnregister(fsPtr) 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 @@ -822,15 +850,14 @@ Tcl_FSUnregister(fsPtr) */ 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; } } @@ -1056,24 +1083,22 @@ Tcl_FSData(fsPtr) 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; } /* @@ -1116,7 +1141,7 @@ TclFSNormalizeToUniquePath(interp, pathPtr, startAt, clientDataPtr) int startAt; ClientData *clientDataPtr; { - FilesystemRecord *fsRecPtr; + FilesystemRecord *fsRecPtr, *firstFsRecPtr; /* Ignore this variable */ (void)clientDataPtr; @@ -1127,7 +1152,9 @@ TclFSNormalizeToUniquePath(interp, pathPtr, startAt, clientDataPtr) * 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; @@ -1138,9 +1165,8 @@ TclFSNormalizeToUniquePath(interp, pathPtr, startAt, clientDataPtr) } fsRecPtr = fsRecPtr->nextPtr; } - FsReleaseIterator(); - fsRecPtr = FsGetIterator(); + fsRecPtr = firstFsRecPtr; while (fsRecPtr != NULL) { /* Skip the native system next time through */ if (fsRecPtr != &nativeFilesystemRecord) { @@ -1158,9 +1184,8 @@ TclFSNormalizeToUniquePath(interp, pathPtr, startAt, clientDataPtr) } fsRecPtr = fsRecPtr->nextPtr; } - FsReleaseIterator(); - return (startAt); + return startAt; } /* @@ -2127,7 +2152,7 @@ Tcl_Obj* Tcl_FSGetCwd(interp) Tcl_Interp *interp; { - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); if (TclFSCwdPointerEquals(NULL)) { FilesystemRecord *fsRecPtr; @@ -2140,7 +2165,7 @@ Tcl_FSGetCwd(interp) * succeeded. */ - fsRecPtr = FsGetIterator(); + fsRecPtr = FsGetFirstFilesystem(); while ((retVal == NULL) && (fsRecPtr != NULL)) { Tcl_FSGetCwdProc *proc = fsRecPtr->fsPtr->getCwdProc; if (proc != NULL) { @@ -2148,7 +2173,6 @@ Tcl_FSGetCwd(interp) } 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 @@ -2162,8 +2186,7 @@ Tcl_FSGetCwd(interp) 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 @@ -2770,7 +2793,7 @@ Tcl_FSListVolumes(void) * a list of all drives from all filesystems. */ - fsRecPtr = FsGetIterator(); + fsRecPtr = FsGetFirstFilesystem(); while (fsRecPtr != NULL) { Tcl_FSListVolumesProc *proc = fsRecPtr->fsPtr->listVolumesProc; if (proc != NULL) { @@ -2782,7 +2805,6 @@ Tcl_FSListVolumes(void) } fsRecPtr = fsRecPtr->nextPtr; } - FsReleaseIterator(); return resultPtr; } @@ -2886,22 +2908,20 @@ Tcl_FSSplitPath(pathPtr, lenPtr) /* 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)) { @@ -2951,7 +2971,7 @@ GetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr, driveNameRef) * matches). */ - fsRecPtr = FsGetIterator(); + fsRecPtr = FsGetFirstFilesystem(); while (fsRecPtr != NULL) { Tcl_FSListVolumesProc *proc = fsRecPtr->fsPtr->listVolumesProc; /* @@ -3025,7 +3045,6 @@ GetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr, driveNameRef) } fsRecPtr = fsRecPtr->nextPtr; } - FsReleaseIterator(); if (type != TCL_PATH_ABSOLUTE) { type = TclpGetNativePathType(pathObjPtr, driveNameLengthPtr, @@ -3405,8 +3424,7 @@ Tcl_FSGetFileSystemForPath(pathObjPtr) * 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; } @@ -3416,7 +3434,7 @@ Tcl_FSGetFileSystemForPath(pathObjPtr) * succeeded. */ - fsRecPtr = FsGetIterator(); + fsRecPtr = FsGetFirstFilesystem(); while ((retVal == NULL) && (fsRecPtr != NULL)) { Tcl_FSPathInFilesystemProc *proc = fsRecPtr->fsPtr->pathInFilesystemProc; if (proc != NULL) { @@ -3427,14 +3445,12 @@ Tcl_FSGetFileSystemForPath(pathObjPtr) * 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; } @@ -3812,7 +3828,7 @@ TclStatInsertProc (proc) } } - return (retVal); + return retVal; } /* @@ -3868,7 +3884,8 @@ TclStatDeleteProc (proc) } Tcl_MutexUnlock(&obsoleteFsHookMutex); - return (retVal); + + return retVal; } /* @@ -3916,7 +3933,7 @@ TclAccessInsertProc(proc) } } - return (retVal); + return retVal; } /* @@ -3972,7 +3989,7 @@ TclAccessDeleteProc(proc) } Tcl_MutexUnlock(&obsoleteFsHookMutex); - return (retVal); + return retVal; } /* @@ -4079,6 +4096,6 @@ TclOpenFileChannelDeleteProc(proc) } Tcl_MutexUnlock(&obsoleteFsHookMutex); - return (retVal); + return retVal; } #endif /* USE_OBSOLETE_FS_HOOKS */ diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index cf9af4f..87ec24b 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclPathObj.c,v 1.5 2003/07/17 00:20:41 hobbs Exp $ + * RCS: @(#) $Id: tclPathObj.c,v 1.6 2003/08/23 12:16:49 vasiljevic Exp $ */ #include "tclInt.h" @@ -24,14 +24,13 @@ * Prototypes for procedures defined later in this file. */ -static void DupFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, - Tcl_Obj *copyPtr)); -static void FreeFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *listPtr)); -static void UpdateStringOfFsPath _ANSI_ARGS_((Tcl_Obj *objPtr)); -static int SetFsPathFromAny _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_Obj *objPtr)); -static int FindSplitPos _ANSI_ARGS_((char *path, char *separator)); - +static void DupFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, + Tcl_Obj *copyPtr)); +static void FreeFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *listPtr)); +static void UpdateStringOfFsPath _ANSI_ARGS_((Tcl_Obj *objPtr)); +static int SetFsPathFromAny _ANSI_ARGS_((Tcl_Interp *interp, + Tcl_Obj *objPtr)); +static int FindSplitPos _ANSI_ARGS_((char *path, char *separator)); /* @@ -504,6 +503,8 @@ Tcl_FSConvertToPathType(interp, objPtr) Tcl_Obj *objPtr; /* Object to convert to a valid, current * path type. */ { + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); + /* * 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 @@ -515,7 +516,7 @@ Tcl_FSConvertToPathType(interp, objPtr) */ if (objPtr->typePtr == &tclFsPathType) { FsPath *fsPathPtr = (FsPath*) PATHOBJ(objPtr); - if (fsPathPtr->filesystemEpoch != theFilesystemEpoch) { + if (fsPathPtr->filesystemEpoch != tsdPtr->filesystemEpoch) { if (objPtr->bytes == NULL) { UpdateStringOfFsPath(objPtr); } @@ -609,6 +610,7 @@ TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len) { FsPath *fsPathPtr; Tcl_Obj *objPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); objPtr = Tcl_NewObj(); fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); @@ -633,13 +635,14 @@ TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len) 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; } @@ -668,6 +671,7 @@ TclFSMakePathRelative(interp, objPtr, cwdPtr) { int cwdLen, len; CONST char *tempStr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); if (objPtr->typePtr == &tclFsPathType) { FsPath* fsPathPtr = (FsPath*) PATHOBJ(objPtr); @@ -701,7 +705,7 @@ TclFSMakePathRelative(interp, objPtr, cwdPtr) Tcl_IncrRefCount(cwdPtr); fsPathPtr->nativePathPtr = NULL; fsPathPtr->fsRecPtr = NULL; - fsPathPtr->filesystemEpoch = theFilesystemEpoch; + fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; PATHOBJ(objPtr) = (VOID *) fsPathPtr; PATHFLAGS(objPtr) = 0; @@ -748,6 +752,7 @@ TclFSMakePathRelative(interp, objPtr, cwdPtr) break; } tempStr = Tcl_GetStringFromObj(objPtr, &len); + return Tcl_NewStringObj(tempStr + cwdLen, len - cwdLen); } @@ -776,6 +781,7 @@ TclFSMakePathFromNormalized(interp, objPtr, nativeRep) * else NULL. */ { FsPath *fsPathPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); if (objPtr->typePtr == &tclFsPathType) { return TCL_OK; @@ -806,7 +812,7 @@ TclFSMakePathFromNormalized(interp, objPtr, nativeRep) fsPathPtr->cwdPtr = NULL; fsPathPtr->nativePathPtr = nativeRep; fsPathPtr->fsRecPtr = NULL; - fsPathPtr->filesystemEpoch = theFilesystemEpoch; + fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; PATHOBJ(objPtr) = (VOID *) fsPathPtr; PATHFLAGS(objPtr) = 0; @@ -850,11 +856,10 @@ Tcl_FSNewNativePath(fromFilesystem, clientData) FsPath *fsPathPtr; FilesystemRecord *fsFromPtr; - int epoch; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); - objPtr = TclFSInternalToNormalized(fromFilesystem, clientData, - &fsFromPtr, &epoch); - + objPtr = TclFSInternalToNormalized(fromFilesystem, clientData, + &fsFromPtr); if (objPtr == NULL) { return NULL; } @@ -876,19 +881,20 @@ Tcl_FSNewNativePath(fromFilesystem, clientData) } 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; } @@ -917,7 +923,9 @@ Tcl_FSGetTranslatedPath(interp, pathPtr) Tcl_Interp *interp; Tcl_Obj* pathPtr; { - register FsPath* srcFsPathPtr; + Tcl_Obj *retObj = NULL; + FsPath *srcFsPathPtr; + if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) { return NULL; } @@ -932,11 +940,13 @@ Tcl_FSGetTranslatedPath(interp, pathPtr) * 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; } /* @@ -964,11 +974,12 @@ Tcl_FSGetTranslatedStringPath(interp, pathPtr) 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; } /* @@ -995,7 +1006,9 @@ Tcl_FSGetNormalizedPath(interp, pathObjPtr) Tcl_Interp *interp; Tcl_Obj* pathObjPtr; { - register FsPath* fsPathPtr; + + FsPath *fsPathPtr; + if (Tcl_FSConvertToPathType(interp, pathObjPtr) != TCL_OK) { return NULL; } @@ -1067,7 +1080,7 @@ Tcl_FSGetNormalizedPath(interp, pathObjPtr) /* 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); @@ -1209,6 +1222,7 @@ Tcl_FSGetNormalizedPath(interp, pathObjPtr) fsPathPtr->cwdPtr = useThisCwd; } } + return fsPathPtr->normPathPtr; } @@ -1239,7 +1253,7 @@ Tcl_FSGetInternalRep(pathObjPtr, fsPtr) Tcl_Obj* pathObjPtr; Tcl_Filesystem *fsPtr; { - register FsPath* srcFsPathPtr; + FsPath* srcFsPathPtr; if (Tcl_FSConvertToPathType(NULL, pathObjPtr) != TCL_OK) { return NULL; @@ -1309,6 +1323,7 @@ Tcl_FSGetInternalRep(pathObjPtr, fsPtr) } srcFsPathPtr->nativePathPtr = (*proc)(pathObjPtr); } + return srcFsPathPtr->nativePathPtr; } @@ -1332,12 +1347,12 @@ Tcl_FSGetInternalRep(pathObjPtr, fsPtr) */ int -TclFSEnsureEpochOk(pathObjPtr, theEpoch, fsPtrPtr) +TclFSEnsureEpochOk(pathObjPtr, fsPtrPtr) Tcl_Obj* pathObjPtr; - int theEpoch; Tcl_Filesystem **fsPtrPtr; { FsPath* srcFsPathPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); /* * SHOULD BE ABLE TO IMPROVE EFFICIENCY HERE. @@ -1353,7 +1368,7 @@ TclFSEnsureEpochOk(pathObjPtr, theEpoch, fsPtrPtr) * 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 @@ -1372,23 +1387,24 @@ TclFSEnsureEpochOk(pathObjPtr, theEpoch, fsPtrPtr) 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(&fsDataKey); /* We assume pathObjPtr is already of the correct type */ FsPath* srcFsPathPtr; srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); srcFsPathPtr->fsRecPtr = fsRecPtr; srcFsPathPtr->nativePathPtr = clientData; - srcFsPathPtr->filesystemEpoch = theEpoch; + srcFsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; fsRecPtr->fileRefCount++; } @@ -1447,6 +1463,7 @@ Tcl_FSEqualPaths(firstPtr, secondPtr) return 1; } } + return 0; } @@ -1480,6 +1497,7 @@ SetFsPathFromAny(interp, objPtr) FsPath *fsPathPtr; Tcl_Obj *transPtr; char *name; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); if (objPtr->typePtr == &tclFsPathType) { return TCL_OK; @@ -1617,13 +1635,14 @@ SetFsPathFromAny(interp, objPtr) */ 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. @@ -1642,7 +1661,7 @@ static void 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) { @@ -1684,9 +1703,9 @@ DupFsPathInternalRep(srcPtr, copyPtr) 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; @@ -1759,7 +1778,7 @@ static void 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; -- cgit v0.12