Attachment "tclIOUtil.c.diff" to
ticket [710642ffff]
added by
vasiljevic
2003-04-02 16:11:44.
--- generic/tclIOUtil.c.orig Thu Jan 1 01:13:01 1970
+++ generic/tclIOUtil.c Fri Mar 28 17:08:35 2003
@@ -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.77 2003/03/03 20:22:41 das Exp $
+ * RCS: @(#) $Id: tclIOUtil.c,v 1.1.1.1 2003/03/08 14:12:47 zoran Exp $
*/
#include "tclInt.h"
@@ -514,11 +514,22 @@
#define TCLPATH_APPENDED 1
#define TCLPATH_RELATIVE 2
+
/*
* Used to implement Tcl_FSGetCwd in a file-system independent way.
* This is protected by the cwdMutex below.
+ *
+ * We deliberately use string instead of Tcl_Obj because it is
+ * not allowed to bounce Tcl_Obj between threads. Furthermore,
+ * Tcl_Obj duplication machinery does not always produce deep
+ * object copies, leaving internal references to other objects,
+ * thus jeopardizing the overall stability if such object ever
+ * crosses the thread boundary.
+ *
+ * Potential limitation of the above is that OS-paths should
+ * really never contain NULL-bytes. Hm...
*/
-static Tcl_Obj* cwdPathPtr = NULL;
+char *cwdPathPtr = NULL;
TCL_DECLARE_MUTEX(cwdMutex)
/*
@@ -546,20 +557,51 @@
/* Now move on to the basic filesystem implementation */
+static void
+FsCwdPointerUpdateInner(objPtr)
+ Tcl_Obj* objPtr;
+{
+ size_t len;
+ char *path = Tcl_GetStringFromObj(objPtr, (int *)&len);
+
+ if (cwdPathPtr != NULL) {
+ Tcl_Free(cwdPathPtr);
+ }
+ cwdPathPtr = memcpy(Tcl_Alloc(len+1), path, len);
+ *(cwdPathPtr + len) = 0;
+}
+
static int
-FsCwdPointerEquals(objPtr)
+FsCwdPointerEqualsInner(objPtr)
Tcl_Obj* objPtr;
{
- Tcl_MutexLock(&cwdMutex);
- if (cwdPathPtr == objPtr) {
- Tcl_MutexUnlock(&cwdMutex);
- return 1;
+ if (objPtr == NULL) {
+ return cwdPathPtr ? 0 : 1;
} else {
- Tcl_MutexUnlock(&cwdMutex);
- return 0;
+ size_t strLen, cwdLen = cwdPathPtr ? strlen(cwdPathPtr) : 0;
+ char *str = Tcl_GetStringFromObj(objPtr, (int *)&strLen);
+ if (strLen != cwdLen) {
+ return 0;
+ } else {
+ return strncmp(str, cwdPathPtr, cwdLen) == 0;
+ }
}
+
+ return 0; /* Never reached */
+}
+
+static int
+FsCwdPointerEquals(objPtr)
+ Tcl_Obj* objPtr;
+{
+ int ret = 0;
+
+ Tcl_MutexLock(&cwdMutex);
+ ret = FsCwdPointerEqualsInner(objPtr);
+ Tcl_MutexUnlock(&cwdMutex);
+
+ return ret;
}
-
static FilesystemRecord*
FsGetIterator(void) {
@@ -612,7 +654,7 @@
*/
if (cwdPathPtr != NULL) {
- Tcl_DecrRefCount(cwdPathPtr);
+ Tcl_Free(cwdPathPtr);
cwdPathPtr = NULL;
}
@@ -2015,7 +2057,7 @@
* This function replaces the library version of getcwd().
*
* Most VFS's will *not* implement a 'cwdProc'. Tcl now maintains
- * its own record (in a Tcl_Obj) of the cwd, and an attempt
+ * its own record (in a char *) of the cwd, and an attempt
* is made to synchronise this with the cwd's containing filesystem,
* if that filesystem provides a cwdProc (e.g. the native filesystem).
*
@@ -2039,13 +2081,6 @@
*
* The result already has its refCount incremented for the caller.
* When it is no longer needed, that refCount should be decremented.
- * This is needed for thread-safety purposes, to allow multiple
- * threads to access this and related functions, while ensuring the
- * results are always valid.
- *
- * Of course it is probably a bad idea for multiple threads to
- * be *setting* the cwd anyway, but we can at least try to
- * help the case of multiple reads with occasional sets.
*
* Side effects:
* Various objects may be freed and allocated.
@@ -2057,9 +2092,11 @@
Tcl_FSGetCwd(interp)
Tcl_Interp *interp;
{
- Tcl_Obj *cwdToReturn;
+ Tcl_Obj *cwdToReturn = NULL;
- if (FsCwdPointerEquals(NULL)) {
+ Tcl_MutexLock(&cwdMutex);
+
+ if (FsCwdPointerEqualsInner(NULL)) {
FilesystemRecord *fsRecPtr;
Tcl_Obj *retVal = NULL;
@@ -2103,14 +2140,7 @@
* we'll always be in the 'else' branch below which
* is simpler.
*/
- Tcl_MutexLock(&cwdMutex);
- /* Just in case the pointer has been set by another
- * thread between now and the test above */
- if (cwdPathPtr != NULL) {
- Tcl_DecrRefCount(cwdPathPtr);
- }
- cwdPathPtr = norm;
- Tcl_MutexUnlock(&cwdMutex);
+ FsCwdPointerUpdateInner(norm);
}
Tcl_DecrRefCount(retVal);
}
@@ -2122,7 +2152,14 @@
* allows an error to be thrown if, say, the permissions on
* that directory have changed.
*/
- Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(cwdPathPtr);
+ Tcl_Filesystem *fsPtr;
+ Tcl_Obj *cwdObj;
+
+ cwdObj = Tcl_NewStringObj(cwdPathPtr, -1);
+ Tcl_IncrRefCount(cwdObj);
+ fsPtr = Tcl_FSGetFileSystemForPath(cwdObj);
+ Tcl_DecrRefCount(cwdObj);
+
/*
* If the filesystem couldn't be found, or if no cwd function
* exists for this filesystem, then we simply assume the cached
@@ -2137,15 +2174,22 @@
if (proc != NULL) {
Tcl_Obj *retVal = (*proc)(interp);
if (retVal != NULL) {
+ int pathEq = 0;
Tcl_Obj *norm = FSNormalizeAbsolutePath(interp, retVal);
/*
* Check whether cwd has changed from the value
* previously stored in cwdPathPtr. Really 'norm'
* shouldn't be null, but we are careful.
*/
+ if (norm != NULL) {
+ cwdObj = Tcl_NewStringObj(cwdPathPtr, -1);
+ Tcl_IncrRefCount(cwdObj);
+ pathEq = Tcl_FSEqualPaths(cwdObj, norm);
+ Tcl_DecrRefCount(cwdObj);
+ }
if (norm == NULL) {
/* Do nothing */
- } else if (Tcl_FSEqualPaths(cwdPathPtr, norm)) {
+ } else if (pathEq) {
/*
* If the paths were equal, we can be more
* efficient and retain the old path object
@@ -2155,21 +2199,14 @@
*/
Tcl_DecrRefCount(norm);
} else {
- /* The cwd has in fact changed, so we must
- * lock down the cwdMutex to modify. */
- Tcl_MutexLock(&cwdMutex);
- Tcl_DecrRefCount(cwdPathPtr);
- cwdPathPtr = norm;
- Tcl_MutexUnlock(&cwdMutex);
+ FsCwdPointerUpdateInner(norm);
}
Tcl_DecrRefCount(retVal);
} else {
/* The 'cwd' function returned an error, so we
- * reset the cwd after locking down the mutex. */
- Tcl_MutexLock(&cwdMutex);
- Tcl_DecrRefCount(cwdPathPtr);
+ * reset the cwd */
+ Tcl_Free(cwdPathPtr);
cwdPathPtr = NULL;
- Tcl_MutexUnlock(&cwdMutex);
}
}
}
@@ -2183,12 +2220,16 @@
* and reading the cwd, and that behaviour is always going to be
* a little suspect.
*/
- Tcl_MutexLock(&cwdMutex);
- cwdToReturn = cwdPathPtr;
+
+ if (cwdPathPtr != NULL) {
+ cwdToReturn = Tcl_NewStringObj(cwdPathPtr, -1);
+ }
+
+ Tcl_MutexUnlock(&cwdMutex);
+
if (cwdToReturn != NULL) {
Tcl_IncrRefCount(cwdToReturn);
}
- Tcl_MutexUnlock(&cwdMutex);
return (cwdToReturn);
}
@@ -2467,8 +2508,11 @@
Tcl_Filesystem *fsPtr;
int retVal = -1;
+ Tcl_MutexLock(&cwdMutex);
+
if (Tcl_FSGetNormalizedPath(NULL, pathPtr) == NULL) {
- return TCL_ERROR;
+ Tcl_MutexUnlock(&cwdMutex);
+ return retVal;
}
fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);
@@ -2511,24 +2555,15 @@
*/
Tcl_Obj *normDirName = Tcl_FSGetNormalizedPath(NULL, pathPtr);
if (normDirName == NULL) {
- return TCL_ERROR;
- }
- /*
- * We will be adding a reference to this object when
- * we store it in the cwdPathPtr.
- */
- Tcl_IncrRefCount(normDirName);
- /* Get a lock on the cwd while we modify it */
- Tcl_MutexLock(&cwdMutex);
- /* Free up the previous cwd we stored */
- if (cwdPathPtr != NULL) {
- Tcl_DecrRefCount(cwdPathPtr);
- }
- /* Now remember the current cwd */
- cwdPathPtr = normDirName;
- Tcl_MutexUnlock(&cwdMutex);
+ retVal = -1;
+ } else {
+ FsCwdPointerUpdateInner(normDirName);
+ retVal = 0;
+ }
}
}
+
+ Tcl_MutexUnlock(&cwdMutex);
return (retVal);
}
@@ -4833,7 +4868,7 @@
/* Get a quick, temporary lock on the cwd while we copy it */
Tcl_MutexLock(&cwdMutex);
- fsPathPtr->cwdPtr = cwdPathPtr;
+ fsPathPtr->cwdPtr = Tcl_NewStringObj(cwdPathPtr, -1);
Tcl_IncrRefCount(fsPathPtr->cwdPtr);
Tcl_MutexUnlock(&cwdMutex);
}