Tcl Source Code

Ticket Change Details
Login
Overview

Artifact ID: b079f464c5e0233328f8b91f4d9401996207eb92a7c26a4994328350115ab2f4
Ticket: 3f7af0e21e13f1f54df4e112d3bf3abb7cfc31dc
win: file delete could sporadic fail with "permission denied"
User & Date: sebres 2018-07-12 13:51:21
Changes

  1. assignee changed to: "nobody"
  2. closer changed to: "nobody"
  3. cmimetype changed to: "text/x-fossil-wiki"
  4. comment changed to:
    Command `file delete $target` fails with "permission denied" under Windows, if another worker checks the same target with file stat (Tcl_FSStat, resp. TclpObjStat) internally, for example by usage of `file mkdir $target`, etc.
    
    I saw this annoying sporadic bug already several times, but thought it going to rude antivirus. Nope!
    
    This is another continuation of latest "race conditions" (this time on the other end and windows only), going to missing flag FILE_SHARE_DELETE in [./artifact?ln=2089-2090&name=e226303aef54a130|NativeStat of tclWinFile.c] in opposite to [./artifact?ln=1654-1655&name=e226303aef54a130|NativeAccess].
    
    I've fixed it already (waiting for test-cases pass) and will merge it hereafter in all branches since 8.5.
    
    As PoC, following script (requires RFE [4f322b9d21]) fill sporadically throw "permission denied" by `file delete` on windows.
    This script (was initially a race condition test-case) tries to create exactly 5 unique temp-folders (.../temp/tcl-test-tmp/0..4) with 5 workers and deletes it after short time.
    After my fix (adding FILE_SHARE_DELETE flag) it does not occur anymore. 
    <code><pre style="padding-left:10pt">
    set prms(path) [file join $::env(TEMP) tcl-test-tmp]
    set prms(thcount) 5
    set prms(repcount) 1000
    set prms(main) [thread::id]
    
    proc ::out {th s} {
      puts "$th $s"
    }
    ## create workers and test-routines:
    set i 0
    time {
      set th($i) [thread::create [string map [list \$\$PRMS [list [array get prms]]] {
        proc out {s} {
          upvar prms prms
          thread::send -async $prms(main) [list out [thread::id] $s]
        }
        proc create-tmp {} {
          upvar prms prms
          set i 0
          while 1 {
            set path [file join $prms(path) $i]
            if {[file mkdir $path]} {
              return $path
            }
            if {[incr cntr] > 10000} { error "endless cycle" }
            if {[incr i] >= $prms(thcount)} {set i 0}
          }
        }
        proc do-test {} {
          array set prms $$PRMS
          if {[catch {
            ## repeat worker task:
            time {
              set path [create-tmp]
              out "++ [file tail $path]"
              file delete -force $path
              out "-- [file tail $path]"
            } $prms(repcount)
            ## done.
          } msg opt]} {
            out "failed with [dict get $opt -errorcode]: $msg"
          }
          thread::send -async $prms(main) {incr ::test_end}
          thread::release
        }
        thread::wait
      }]]
      incr i
    } $prms(thcount)
    
    ## start in all workers:
    set ::test_end 0
    file delete -force $prms(path)
    set i 0
    time {
      thread::send -async $th($i) do-test
      incr i
    } $prms(thcount)
    
    ## wait until all workers get ready and cleanup:
    set ev [after 60000 [list set ::test_end $prms(thcount)]]
    while {$::test_end < $prms(thcount)} {vwait ::test_end}
    after cancel $ev
    file delete -force $prms(path)
    </pre></code>
    
  5. foundin changed to: ">= 8.5"
  6. is_private changed to: "0"
  7. login: "sebres"
  8. priority changed to: "5 Medium"
  9. resolution changed to: "None"
  10. severity changed to: "Minor"
  11. status changed to: "Open"
  12. submitter changed to: "sebres"
  13. subsystem changed to: "- New Builtin Commands"
  14. title changed to:
    win: file delete could sporadic fail with "permission denied"
    
  15. type changed to: "Bug"