Repository: JuliaLang/julia
File: base/file.jl (Julia)

Code before:
    @lock TEMP_CLEANUP_LOCK filter!(TEMP_CLEANUP) do (path, asap)
        try
            ispath(path) || return false
            may_need_gc = true
            return true
        catch ex
            ex isa InterruptException && rethrow()
            return true
        end
    end
    if may_need_gc
        # this is only usually required on Sys.iswindows(), but may as well do it everywhere
        GC.gc(true)
    end
    @lock TEMP_CLEANUP_LOCK temp_cleanup_purge_prelocked(true)
    nothing
end

# deprecated internal function used by some packages
temp_cleanup_purge(; force=false) = force ? temp_cleanup_purge_all() : @lock TEMP_CLEANUP_LOCK temp_cleanup_purge_prelocked(false)

function temp_cleanup_postprocess(cleanup_dirs)
    if !isempty(cleanup_dirs)
        rmcmd = """
        eof(stdin)
        for path in eachline(stdin)
            try
                rm(path, force=true, recursive=true)
            catch ex
                @warn "Failed to clean up temporary path \$(repr(path))\n\$ex" _group=:file
            end
        end
        """
        cmd = Cmd(Base.cmd_gen(((Base.julia_cmd(),), ("--startup-file=no",), ("-e",), (rmcmd,))); ignorestatus = true, detach = true)
        pw = Base.PipeEndpoint()
        rd, wr = Base.link_pipe(true, true)
        try
            Base.open_pipe!(pw, wr)
        catch
            Base.close_pipe_sync(wr)
            rethrow()
        end
        run(cmd, rd, devnull, stderr; wait=false)
        join(pw, cleanup_dirs, "\n")
        Base.dup(wr) # intentionally leak a reference, until the process exits
        close(pw)
    end
end

function temp_cleanup_atexit()
    temp_cleanup_purge_all()

Review comment (bug):
```suggestion
        cleanuplist = readlines(stdin) # This loop won't start running until stdin is closed, which is supposed to be sequenced after the process exits
        sleep(1) # Wait for the operating system to hopefully be ready, since the OS implementation is probably incorrect, given the history of buggy work-arounds like this that have existed for ages in dotNet and libuv
        for path in cleanuplist
```

Code after:

function temp_cleanup_purge_all()
    may_need_gc = false
    @lock TEMP_CLEANUP_LOCK filter!(TEMP_CLEANUP) do (path, asap)
        try
            ispath(path) || return false
            may_need_gc = true
            return true
        catch ex
            ex isa InterruptException && rethrow()
            return true
        end
    end
    if may_need_gc
        # this is only usually required on Sys.iswindows(), but may as well do it everywhere
        GC.gc(true)
    end
    @lock TEMP_CLEANUP_LOCK temp_cleanup_purge_prelocked(true)
    nothing
end

# deprecated internal function used by some packages
temp_cleanup_purge(; force=false) = force ? temp_cleanup_purge_all() : @lock TEMP_CLEANUP_LOCK temp_cleanup_purge_prelocked(false)

function temp_cleanup_postprocess(cleanup_dirs)
    if !isempty(cleanup_dirs)
        rmcmd = """
        cleanuplist = readlines(stdin) # This loop won't start running until stdin is closed, which is supposed to be sequenced after the process exits
        sleep(1) # Wait for the operating system to hopefully be ready, since the OS implementation is probably incorrect, given the history of buggy work-arounds like this that have existed for ages in dotNet and libuv
        for path in cleanuplist
            try
                rm(path, force=true, recursive=true)
            catch ex
                @warn "Failed to clean up temporary path \$(repr(path))\n\$ex" _group=:file
            end
        end
        """
        cmd = Cmd(Base.cmd_gen(((Base.julia_cmd(),), ("--startup-file=no",), ("-e",), (rmcmd,))); ignorestatus = true, detach = true)
        pw = Base.PipeEndpoint()
        run(cmd, pw, devnull, stderr; wait=false)
        join(pw, cleanup_dirs, "\n")
        Base.dup(Base._fd(pw)) # intentionally leak a reference, until the process exits
        close(pw)
    end
end

function temp_cleanup_atexit()
    temp_cleanup_purge_all()
    @lock TEMP_CLEANUP_LOCK temp_cleanup_postprocess(keys(TEMP_CLEANUP))
end