Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | More work in progress. The problem with release of the elements of a fileSystemList by one routine while some other (caller) routine is still traversing that list is not dependent on threaded operations. An unthreaded build can still encounter the problem. Revised so that threaded/unthreaded operations are much closer to the same (no direct TCL_THREADS dependency). Also simplified the epoch checking which reduces locking to when it's needed. Still have the problem of returning as valid FilesystemRecords that are pulled from an outdated epoch. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | bug-3024359 |
Files: | files | file ages | folders |
SHA1: |
223bd04c8b4fcdd50ca609acd2a7211d |
User & Date: | dgp 2012-06-13 17:26:41 |
Context
2012-06-18
| ||
20:36 | Next draft fix. This one appears to solve the problem, at least as demo'd by the test attached to T... check-in: dea555ba83 user: dgp tags: bug-3024359 | |
2012-06-13
| ||
17:26 | More work in progress. The problem with release of the elements of a fileSystemList by one routine w... check-in: 223bd04c8b user: dgp tags: bug-3024359 | |
2012-06-12
| ||
13:44 | Convert function calls to macros. check-in: eefb9a9fee user: dgp tags: bug-3024359 | |
Changes
Changes to generic/tclIOUtil.c.
︙ | ︙ | |||
35 36 37 38 39 40 41 | static void FsThrExitProc(ClientData cd); static Tcl_Obj * FsListMounts(Tcl_Obj *pathPtr, const char *pattern); static void FsAddMountsToGlobResult(Tcl_Obj *resultPtr, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); static void FsUpdateCwd(Tcl_Obj *cwdObj, ClientData clientData); | < < < < < | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | static void FsThrExitProc(ClientData cd); static Tcl_Obj * FsListMounts(Tcl_Obj *pathPtr, const char *pattern); static void FsAddMountsToGlobResult(Tcl_Obj *resultPtr, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); static void FsUpdateCwd(Tcl_Obj *cwdObj, ClientData clientData); static void FsRecacheFilesystemList(void); static void Purge(FilesystemRecord *fsRecPtr); #define Claim() (tsdPtr->claims++) #define Disclaim() if (--tsdPtr->claims <= 0) Purge(tsdPtr->filesystemList); /* * These form part of the native filesystem support. They are needed here * because we have a few native filesystem functions (which are the same for * win/unix) in this file. There is no need to place them in tclInt.h, because * they are not (and should not be) used anywhere else. */ |
︙ | ︙ | |||
586 587 588 589 590 591 592 | return 1; } else { return 0; } } } | < | 581 582 583 584 585 586 587 588 589 590 591 592 593 594 | return 1; } else { return 0; } } } static void FsRecacheFilesystemList(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); FilesystemRecord *fsRecPtr, *tmpFsRecPtr = NULL; /* |
︙ | ︙ | |||
610 611 612 613 614 615 616 | } fsRecPtr = tmpFsRecPtr; } tsdPtr->filesystemList = NULL; } /* | < < < > > > < < < < < < < < < | < < < < | < | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 | } fsRecPtr = tmpFsRecPtr; } tsdPtr->filesystemList = NULL; } /* * Locate tail of the global filesystem list. */ Tcl_MutexLock(&filesystemMutex); 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; tsdPtr->filesystemList = tmpFsRecPtr; fsRecPtr = fsRecPtr->prevPtr; } tsdPtr->filesystemEpoch = theFilesystemEpoch; Tcl_MutexUnlock(&filesystemMutex); /* * Make sure the above gets released on thread exit. */ if (tsdPtr->initialized == 0) { Tcl_CreateThreadExitHandler(FsThrExitProc, (ClientData) tsdPtr); tsdPtr->initialized = 1; } } static FilesystemRecord * FsGetFirstFilesystem(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); if (tsdPtr->filesystemList == NULL || (tsdPtr->filesystemEpoch != theFilesystemEpoch)) { FsRecacheFilesystemList(); } return tsdPtr->filesystemList; } /* * The epoch can be changed both by filesystems being added or removed and by * env(HOME) changing. */ int TclFSEpochOk( int filesystemEpoch) { return (filesystemEpoch == theFilesystemEpoch); } static void Purge( FilesystemRecord *fsRecPtr) { FilesystemRecord *toRelease; /* |
︙ | ︙ | |||
708 709 710 711 712 713 714 | if (--toRelease->fileRefCount <= 0) { ckfree((char *)toRelease); } toRelease = fsRecPtr; } } | < | 688 689 690 691 692 693 694 695 696 697 698 699 700 701 | if (--toRelease->fileRefCount <= 0) { ckfree((char *)toRelease); } toRelease = fsRecPtr; } } /* * If non-NULL, clientData is owned by us and must be freed later. */ static void FsUpdateCwd( |
︙ | ︙ | |||
828 829 830 831 832 833 834 835 836 837 838 839 840 841 | if (fsRecPtr->fsPtr != &tclNativeFilesystem) { ckfree((char *)fsRecPtr); } } fsRecPtr = tmpFsRecPtr; } filesystemList = NULL; /* * Now filesystemList is NULL. This means that any attempt to use the * filesystem is likely to fail. */ | > | 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 | if (fsRecPtr->fsPtr != &tclNativeFilesystem) { ckfree((char *)fsRecPtr); } } fsRecPtr = tmpFsRecPtr; } theFilesystemEpoch++; filesystemList = NULL; /* * Now filesystemList is NULL. This means that any attempt to use the * filesystem is likely to fail. */ |
︙ | ︙ | |||
865 866 867 868 869 870 871 872 873 874 875 876 877 878 | *---------------------------------------------------------------------- */ void TclResetFilesystem(void) { filesystemList = &nativeFilesystemRecord; /* * Note, at this point, I believe nativeFilesystemRecord -> fileRefCount * should equal 1 and if not, we should try to track down the cause. */ #ifdef __WIN32__ | > | 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 | *---------------------------------------------------------------------- */ void TclResetFilesystem(void) { filesystemList = &nativeFilesystemRecord; theFilesystemEpoch++; /* * Note, at this point, I believe nativeFilesystemRecord -> fileRefCount * should equal 1 and if not, we should try to track down the cause. */ #ifdef __WIN32__ |
︙ | ︙ | |||
1447 1448 1449 1450 1451 1452 1453 | Tcl_Interp *interp, /* Used for error messages. */ Tcl_Obj *pathPtr, /* The path to normalize in place */ int startAt, /* Start at this char-offset */ ClientData *clientDataPtr) /* If we generated a complete normalized path * for a given filesystem, we can optionally * return an fs-specific clientdata here. */ { | < < | 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 | Tcl_Interp *interp, /* Used for error messages. */ Tcl_Obj *pathPtr, /* The path to normalize in place */ int startAt, /* Start at this char-offset */ ClientData *clientDataPtr) /* If we generated a complete normalized path * for a given filesystem, we can optionally * return an fs-specific clientdata here. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); FilesystemRecord *fsRecPtr, *firstFsRecPtr; /* Ignore this variable */ (void) clientDataPtr; /* * Call each of the "normalise path" functions in succession. This is a * special case, in which if we have a native filesystem handler, we call |
︙ | ︙ | |||
3682 3683 3684 3685 3686 3687 3688 | * *--------------------------------------------------------------------------- */ Tcl_Obj* Tcl_FSListVolumes(void) { | < < | 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 | * *--------------------------------------------------------------------------- */ Tcl_Obj* Tcl_FSListVolumes(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); FilesystemRecord *fsRecPtr; Tcl_Obj *resultPtr = Tcl_NewObj(); /* * Call each of the "listVolumes" function in succession. A non-NULL * return value indicates the particular function has succeeded. We call * all the functions registered, since we want a list of all drives from |
︙ | ︙ | |||
3739 3740 3741 3742 3743 3744 3745 | */ static Tcl_Obj * FsListMounts( Tcl_Obj *pathPtr, /* Contains path to directory to search. */ const char *pattern) /* Pattern to match against. */ { | < < | 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 | */ static Tcl_Obj * FsListMounts( Tcl_Obj *pathPtr, /* Contains path to directory to search. */ const char *pattern) /* Pattern to match against. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); FilesystemRecord *fsRecPtr; Tcl_GlobTypeData mountsOnly = { TCL_GLOB_TYPE_MOUNT, 0, NULL, NULL }; Tcl_Obj *resultPtr = NULL; /* * Call each of the "matchInDirectory" functions in succession, with the * specific type information 'mountsOnly'. A non-NULL return value |
︙ | ︙ | |||
3888 3889 3890 3891 3892 3893 3894 | /* Simple helper function */ Tcl_Obj * TclFSInternalToNormalized( Tcl_Filesystem *fromFilesystem, ClientData clientData, FilesystemRecord **fsRecPtrPtr) { | < < | 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 | /* Simple helper function */ Tcl_Obj * TclFSInternalToNormalized( Tcl_Filesystem *fromFilesystem, ClientData clientData, FilesystemRecord **fsRecPtrPtr) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); FilesystemRecord *fsRecPtr = FsGetFirstFilesystem(); Claim(); while (fsRecPtr != NULL) { if (fsRecPtr->fsPtr == fromFilesystem) { *fsRecPtrPtr = fsRecPtr; break; |
︙ | ︙ | |||
4008 4009 4010 4011 4012 4013 4014 | * driveName. */ Tcl_Obj **driveNameRef) /* If the path is absolute, and this is * non-NULL, then set to the name of the * drive, network-volume which contains the * path, already with a refCount for the * caller. */ { | < < | 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 | * driveName. */ Tcl_Obj **driveNameRef) /* If the path is absolute, and this is * non-NULL, then set to the name of the * drive, network-volume which contains the * path, already with a refCount for the * caller. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); FilesystemRecord *fsRecPtr; Tcl_PathType type = TCL_PATH_RELATIVE; /* * Call each of the "listVolumes" function in succession, checking whether * the given path is an absolute path on any of the volumes returned (this * is done by checking whether the path's prefix matches). |
︙ | ︙ | |||
4471 4472 4473 4474 4475 4476 4477 | *--------------------------------------------------------------------------- */ Tcl_Filesystem * Tcl_FSGetFileSystemForPath( Tcl_Obj* pathPtr) { | < < | 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 | *--------------------------------------------------------------------------- */ Tcl_Filesystem * Tcl_FSGetFileSystemForPath( Tcl_Obj* pathPtr) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); FilesystemRecord *fsRecPtr; Tcl_Filesystem* retVal = NULL; if (pathPtr == NULL) { Tcl_Panic("Tcl_FSGetFileSystemForPath called with NULL object"); return NULL; } |
︙ | ︙ |