Tcl Source Code

View Ticket
Login
Ticket UUID: 439114
Title: Channel buffering affects [close] status
Type: Bug Version: obsolete: 8.4a3
Submitter: chris_nelson Created on: 2001-07-06 16:52:51
Subsystem: 25. Channel System Assigned To: andreas_kupries
Priority: 5 Medium Severity:
Status: Open Last Modified: 2001-12-14 03:19:41
Resolution: None Closed By:
    Closed on:
Description:
When running a child process on a open pipe, the buffering of the channel appears to affect the 
[catch] of the [close] of the channel on [eof].

I'll attach a script which reproduce this problem.  A C program which can be used to demonstrate it 
is:

  #include <stdio.h>

  int main(int argc,char **argv)
  {
      fprintf(stderr, "child.c   : About To Exit NonZero...\n");
      exit(33);
  }

When run in Tcl 8.2, the parent process correctly gets the child's exit status.  When run in Tcl, the 
child process appears to always succeed.

 urchin{53}hyper/v5.0.3/eofError > /usr/local/bin/tclsh8.2
 % source t.tcl
 % works
 child.c   : About To Exit NonZero...
 <<>>Got EOF on file3
         Set FioStatus to 1 from catch of close
         errorCode:CHILDSTATUS 9311 33
 PtiExec(FioStatus):1
 % fails
 child.c   : About To Exit NonZero...
 <<>>Got EOF on file3
         Set FioStatus to 1 from catch of close
         errorCode:CHILDSTATUS 9312 33
 PtiExec(FioStatus):1
 % urchin{54}hyper/v5.0.3/eofError > /usr/local/bin/tclsh8.4
 % source t.tcl
 % works
 child.c   : About To Exit NonZero...
 <<>>Got EOF on file3
         Set FioStatus to 1 from catch of close
         errorCode:CHILDSTATUS 9316 33
 PtiExec(FioStatus):1
 % fails
 child.c   : About To Exit NonZero...
 <<>>Got EOF on file3
        Set FioStatus to 0 from catch of close
        errorCode:CHILDSTATUS 9316 33
 PtiExec(FioStatus):0
User Comments: chris_nelson added on 2001-12-14 03:19:41:
Logged In: YES 
user_id=107514

I looked a bit but got dizzy looking at unfamiliar channel and process management code.  Sorry.

andreas_kupries added on 2001-12-14 01:15:38:
Logged In: YES 
user_id=75003

Chris, did you have the time to "look into how to determine 
if the child is done or not" ?

chris_nelson added on 2001-07-13 22:19:42:
Logged In: YES 
user_id=107514

OK.  The problem seems to be in PipeCloseProc which says:

    if (pipePtr->isNonBlocking || TclInExit()) {
    
        /*
         * If the channel is non-blocking or Tcl is being cleaned up, just
         * detach the children PIDs, reap them (important if we are in a
         * dynamic load module), and discard the errorFile.
         */
        
        Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr);
        Tcl_ReapDetachedProcs();

        if (pipePtr->errorFile) {
    TclpCloseFile(pipePtr->errorFile);
        }
    } else {
        
        /*
         * Wrap the error file into a channel and give it to the cleanup
         * routine.
         */

        if (pipePtr->errorFile) {
    errChan = Tcl_MakeFileChannel(
(ClientData) GetFd(pipePtr->errorFile), TCL_READABLE);
        } else {
            errChan = NULL;
        }
        result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr,
                errChan);
    }

The first clause isn't specific enough, we only want to discard or ignore the child's status if the child is still 
running.  If the pipe is nonblocking BUT the child is done, we _can_ (and should!) get the child's exit status. 
I'm looking into how to determine if the child is done or not.

chris_nelson added on 2001-07-13 20:55:07:
Logged In: YES 
user_id=107514

I guess I _was_ seeing aborts but I was ignoring them and could get rid of them by removing an 
unnecessary command:

     fconfigure stdout -buffering none -blocking 0 -translation binary

I see that dropping the child status showed up in 8.2.3 and that I should look at tclUnixPipe.c.  Thanks.

dgp added on 2001-07-13 05:38:36:
Logged In: YES 
user_id=80530

OK, the particular change between 8.2.2 and 8.3.3 releases
that changed the behavior is that noted in the Changelog:

1999-11-29  Jeff Hobbs  <[email protected]>

        * unix/tclUnixPipe.c: fixed PipeBlockModeProc to
properly set
        isNonBlocking flag on pipe. [Bug: 1356 710]
        removed spurious fcntl call from PipeBlockModeProc

You can restore the 8.2.2 behavior by commenting out
line 836 of revision 1.12 of unix/tclUnixPipe.c .  Just
tested that on the HEAD revision.  That's just information,
not a recommendation.

FYI, Bugs 1356 and 710 are now known as Bugs 218588
and 218492, respectively.

dgp added on 2001-07-13 05:16:15:
Logged In: YES 
user_id=80530

Thanks for including the test scripts.  They help a lot.

Now the bad news.  Your test scripts fail on all releases
of Tcl that I've tested:

$ tclsh7.6
% source t.tcl
% works
child.c : About To Exit NonZero...
<<>>Got EOF on file3
        Set FioStatus to 1 from catch of close
        errorCode:$::errorCode
can't wait for variable "::PtiExec(FioDone)":  would wait
forever
% fails
child.c : About To Exit NonZero...
<<>>Got EOF on file3
        Set FioStatus to 1 from catch of close
        errorCode:$::errorCode
can't wait for variable "::PtiExec(FioDone)":  would wait
forever
% exit

$ tclsh8.0
% info patch
8.0.5
% source t.tcl
% works
child.c : About To Exit NonZero...
<<>>Got EOF on file3
        Set FioStatus to 1 from catch of close
        errorCode:CHILDSTATUS 16053 33
PtiExec(FioStatus):1
% fails
child.c : About To Exit NonZero...
<<>>Got EOF on file3
        Set FioStatus to 1 from catch of close
        errorCode:CHILDSTATUS 16054 33
PtiExec(FioStatus):1
% Blocking channel driver did not block on input
Abort

$ tclsh8.1
% info patch
8.1.1
% source t.tcl
% works
child.c : About To Exit NonZero...
<<>>Got EOF on file3
        Set FioStatus to 1 from catch of close
        errorCode:CHILDSTATUS 16057 33
PtiExec(FioStatus):1
% fails
child.c : About To Exit NonZero...
<<>>Got EOF on file3
        Set FioStatus to 1 from catch of close
        errorCode:CHILDSTATUS 16058 33
PtiExec(FioStatus):1
% $

Note that the script aborts tclsh8.1, but there is no
panic message this time.  This same behavior is also
observed in 8.2.0 and 8.2.1 and 8.2.2.

Then in 8.2.3:

$ tclsh8.2
% info patch
8.2.3
% source t.tcl
% works
child.c : About To Exit NonZero...
<<>>Got EOF on file3
        Set FioStatus to 1 from catch of close
        errorCode:CHILDSTATUS 25060 33
PtiExec(FioStatus):1
% fails
child.c : About To Exit NonZero...
<<>>Got EOF on file3
        Set FioStatus to 0 from catch of close
        errorCode:CHILDSTATUS 25060 33
PtiExec(FioStatus):0
% $

Now the [close] doesn't throw an error, which seems to
be the bug you are reporting, so that misbehavior first
showed up in Tcl 8.2.3, but notice the tclsh still aborts!

That behavior is also exhbited by 8.3.3 and 8.4a3, and I'm
assuming also all the 8.3.x and 8.4ax releases.   Except
for the aborting, that's what you report for 8.4a3 as well.

You don't see aborts?

So, anyway, I'd look into the changes between 8.2.2 and
8.2.3 for the cause of the change in behavior of [close],
but I don't see any version of Tcl (on Solaris 8) for which
your scripts will work.

dgp added on 2001-07-13 02:23:17:

File Added - 8354: child.c

chris_nelson added on 2001-07-06 23:52:52:

File Added - 8135: t.tcl

Attachments: