http://qs321.pair.com?node_id=1039340


in reply to Re: Win32: Setting a layer with binmode causes problem with close() on Windows (PerlIO silently fails to close the file)
in thread Win32: Setting a layer with binmode causes problem with close() on Windows

Good analysis, but I think you have it wrong in one point: At the time when the unlink fails, no other processes are running which have a hold on the file: The one which had created the file is not running anymore (since system waits for the child process to finish), and - just for completion - the process deleting the file has not started yet.

BTW, Both system calls don't exist in my original code in this way (in my application, the file is created on a Unix host asynchroniously, and read and deleted from the Windows process). I have introduced them in the example for the following reason:

-- 
Ronald Fischer <ynnor@mm.st>

Replies are listed 'Best First'.
Re^3: Win32: Setting a layer with binmode causes problem with close() on Windows (PerlIO silently fails to close the file)
by BrowserUk (Patriarch) on Jun 17, 2013 at 11:55 UTC
    I think you have it wrong in one point: At the time when the unlink fails, no other processes are running which have a hold on the file:

    Here's the problem. You know the way you have to fork twice under *nix in order to deamonise a process -- the first fork inherits loads of handles (stdin, stdout, stderr etc.) from its parent; so you then close them and fork again to get a process that true independent of its parent -- well similar things can happen under windows.

    system starts a new process that inherits lots of stuff from it parent. When it dies, if the parent is still around, many of those shared (duped) handles have to be retained within the kernel -- waiting for all their duplicates to be marked for delete -- and despite that the process has been removed from the system scheduler, those retained, open, shared handles will still be attributed to that now defunct process. So, the fact that system has returned does not mean all of it resources have been cleaned up.

    My simplified version of the test script simply removes all of those possibilities and demonstrates that the only process that could have a handle to the file is the perl process itself. Which is then verified using an external tool (handle.exe).

    Thus it is the close that is failing silently.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      So, the fact that system has returned does not mean all of it resources have been cleaned up.
      Oh my! I didn't think about this issue! But this would mean that it is unsafe to have an (external) process create a file, and then use it in my program - at least under Windows, which is very picky about this kind of stuff? If I understand you right, this should even true if we use IPC::Run to run the process. OTOH, this scenario - running an utility to create a file, then use it - is so common, that I wonder why we are not bitten by this more often. Or is there a clever, safe way to achieve the goal?

      -- 
      Ronald Fischer <ynnor@mm.st>
        I didn't think about this issue! But this would mean that it is unsafe to have an (external) process create a file, and then use it in my program - at least under Windows, which is very picky about this kind of stuff?

        Here's the thing. If you want to delete a file that you've been accessing, from the script you've been accessing it from, you need close it first. If you've also run some commands via system that accessed that file, and they have left open, duped handles in the kernel, they will disappear as soon as you close your handle.

        So normally, the problem does not arise. Indeed you can verify this by running your OP code with the binmode commented out.

        It was only necessary to remove all the subprocesses from your example in order to confirm, by dint of 'it couldn't be anything else', that is was the perl process that was holding the open handle.

        It then becomes clear that the "other process" is actually 'this process'; and thus the close is failing silently when binmode has added the ':unix' IO layer to the stack.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        something like this

        sub system_detached { my $program; my @args ; my $cmdline; if( @_ > 1 ){ ( $program ) = @_; $cmdline = Win32::ShellQuote::quote_system_string( @_ ); } else { ( $cmdline ) = @_; } $!=$^E=0; my $ProcessObj; ## http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v= +vs.85).aspx# CreateProcess function (Windows) ## http://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v= +vs.85).aspx# Process Creation Flags (Windows) use Win32::ShellQuote(); use Win32::Process(); Win32::Process::Create( $ProcessObj, $program, $cmdline, 0, # don't inherit handles Win32::Process::DETACHED_PROCESS(), ".", #cwd ) or do { my $err = int($!).' '.$!." #### ".int($^E)." $^E "; warn "??CreateProcess failed (\$ProcessObj $ProcessObj) $err " +; return; }; return $ProcessObj; }