in reply to Re^4: Pipes and IO::Select's method can_write()
in thread Pipes and IO::Select's method can_write()

I was mainly just wondering why the can_write() method does essentially say "Yes, I can write", if it can't...

The underlying function is called select. can_write is a misnomer. It doesn't alert of the ability to write. It alerts the receipt of a write event. The inability to write is a write event.

you get exactly the same behaviour, if the child is still alive, but doesn't take input (as when explicitly having closed STDIN)

In both cases, the child explicitly closed STDIN. In both cases, the child is not (completely) dead. It only disappears after waitpid allows it to die.

why it can't figure out that there is some problem on the other end (or, at least, doesn't tell you)

But that's exactly what it does! select tells you there's an event, and syswrite tells you what the event is. It's convenient how you are saved from making a third system call.

Something else that might be of interest is knowing when a child becomes a zombie. I don't know if unix allows you to be alerted of such an event, but it can be determined by polling waitpid($pid, WNOHANG).

Replies are listed 'Best First'.
Re^6: Pipes and IO::Select's method can_write()
by sgt (Deacon) on Feb 02, 2007 at 23:14 UTC
    In both cases, the child is not (completely) dead. It only disappears after waitpid allows it to die.

    I feel this phrasing is slightly misleading...

    ZOMBIE is the final state of a process (It does not "run" anymore). In that state all ressources used by the process are freed, all except one, the slot corresponding to the process in the kernel process table. If the father of that process is not a daemon and finishes eventually (even without handling /SIGC(H)?LD/) then the process is orphaned and init will reclaim it . If the father is a daemon then it *must* handle /SIGC(H)?LD/ or there is potential for the system process table to fill up. After that chaos is guaranteed, as nobody can fork!

    Some systems allow a process to ignore /SIGC(H)?ILD/ so that the system does the reaping for it. I think it's POSIX but not (yet) fully portable. Note Un*x does not do this reaping systematically as the information is useful especially if you just want to control a pool of processes etc...The single UNIX spec (since 98 I think -- at least my HP-UX 11.0 manpage says so) does sanctify the "ignore" shortcut.

    cheers --stephan
Re^6: Pipes and IO::Select's method can_write() (blocking)
by tye (Sage) on Feb 02, 2007 at 23:49 UTC

    "can_write" is actually short for "can write without blocking". If trying to write will immediately fail, then it won't block, which is what select cares about (and so makes "can write" true). Just like if reading will immediately fail because of end-of-stream or because of an error, then "can read" becomes true because trying to read won't block ("hang").

    - tye        

      Actually the only guarantee for writing is 1 byte (supposing you don't get an error) so if you try to write more you might block, that's why if you don't want to be blocked you need to go all the way to non-blocking handles (which is never easy as you have to deal with partial writes).

      If I need to go non-blocking I usually use a variation on Lincoln's Stein IO::SessionData and IO::SessionSet. Sadly they are packaged with SOAP::Lite, and having "godzilla" as a prerequesite is no fun ;) IO::Multiplex is also interesting.

      hth --stephan

        Interesting. I thought syswrite would only write as much as it could without blocking, but my test (on FreeBSD 6.1) shows otherwise.

        Test:

        use strict; use warnings; use IO::Handle qw( ); use IO::Select qw( ); { pipe(my $fh_r, my $fh_w) or die("Unable to create pipe: $!\n"); $fh_w->autoflush(1); my $sel_w = IO::Select->new($fh_w); { print("Filling up the pipe...\n"); my $buf = 'x'; for (;;) { my @ready_w = $sel_w->can_write(0.5); # Pipe is full! last if not @ready_w; die if @ready_w != 1; die if $ready_w[0] != $fh_w; my $rv = syswrite($fh_w, $buf, length($buf)); if (not defined $rv) { die("Unable to write to the pipe: $!\n"); } if (not $rv) { die("Unable to write to the pipe: 0 bytes written??\n"); } } } { print("Opening up one byte in the pipe...\n"); my $buf = ''; my $rv = sysread($fh_r, $buf, 1); if (not defined $rv) { die("Unable to read from the pipe: $!\n"); } if (not $rv) { die("Unable to read from the pipe: 0 bytes read??\n"); } } { print("Make sure it's safe to write to the pipe...\n"); my @ready_w = $sel_w->can_write(); die if @ready_w != 1; die if $ready_w[0] != $fh_w; } { print("Writing more chars to the pipe than the pipe can handle.. +.\n"); my $buf = 'x' x (1024*1024); my $rv = syswrite($fh_w, $buf, length($buf)); if (not defined $rv) { die("Unable to write to the pipe [2]: $!\n"); } if (not $rv) { die("Unable to write to the pipe [2]: 0 bytes written??\n"); } printf("Wrote %d bytes to the pipe\n", $rv); } close($fh_w); close($fh_r); }

        Output:

        Filling up the pipe... Opening up one byte in the pipe... Make sure it's safe to write to the pipe... Writing more chars to the pipe than the pipe can handle... [blocks]

        That's unfortunate.