in reply to Re^2: Diagnosing blocking io (or: finding the WHY of my Open2 woes).
in thread Diagnosing blocking io (or: finding the WHY of my Open2 woes).

Your program works fine for me when I run a Perl script for the child.

my $pid = open2($JSREAD, $JSWRITE, q{perl -e"{ $_=<>; last if /^END$/; + ++$i; $m=qq{$i: $_}; warn $m; print $m; redo}"});

(The $|=1 isn't even necessary!)

Seems to me the problem is in the js side. But I doubt it's in readline. Are you sure your Perl script reaches END? Are you sure END is causing the child to exit?

By the way, you're adding newlines where they already exist in two different places.

Replies are listed 'Best First'.
Re^4: Diagnosing blocking io (or: finding the WHY of my Open2 woes).
by Socrates (Acolyte) on Nov 19, 2008 at 14:32 UTC

    Yes, you're right about the unnecessary newlines. I fixed the newline where it feeds the file one line at a time to the child. The perl absolutely reaches "END".

    test.js is three simple lines:

    var foo=0; var bar=1; var baz=2;

    And I can type these in, one at a time, into the running javascript program from the command line:

    $ js js> load('jslint.js'); var foo=0; var bar=1; var baz=3; END jslint: No problems found. $

    If I drop warns in:

    open FILE, '<', "test.js"; while (<FILE>) { warn "printing $_"; print $JSWRITE "$_"; } close(FILE); warn "printing END\n"; print $JSWRITE "END\n";

    I see:

    $ ./jslint.pl printing var foo=0; printing var bar=1; printing var baz=3; printing END

    And strace shows this:

    ... write(4, "load(\'jslint.js\');\n", 19) = 19 open("test.js", O_RDONLY) = 3 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff8d5e9440) = -1 ENOTTY (I +nappropriate ioctl for device) lseek(3, 0, SEEK_CUR) = 0 fstat(3, {st_mode=S_IFREG|0664, st_size=33, ...}) = 0 fcntl(3, F_SETFD, FD_CLOEXEC) = 0 read(3, "var foo=0;\nvar bar=1;\nvar baz=3;"..., 4096) = 33 write(2, "printing var foo=0;\n", 20printing var foo=0; ) = 20 write(4, "var foo=0;\n", 11) = 11 write(2, "printing var bar=1;\n", 20printing var bar=1; ) = 20 write(4, "var bar=1;\n", 11) = 11 write(2, "printing var baz=3;\n", 20printing var baz=3; ) = 20 write(4, "var baz=3;\n", 11) = 11 read(3, "", 4096) = 0 close(3) = 0 write(2, "printing END\n", 13printing END ) = 13 write(4, "END\n", 4) = 4 close(4) = 0 read(5, <unfinished ...>

    Which, if I remove reading from $JSREAD, becomes:

    write(4, "load(\'jslint.js\');\n", 19) = 19 open("test.js", O_RDONLY) = 3 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff38afb950) = -1 ENOTTY (I +nappropriate ioctl for device) lseek(3, 0, SEEK_CUR) = 0 fstat(3, {st_mode=S_IFREG|0664, st_size=33, ...}) = 0 fcntl(3, F_SETFD, FD_CLOEXEC) = 0 read(3, "var foo=0;\nvar bar=1;\nvar baz=3;"..., 4096) = 33 write(2, "printing var foo=0;\n", 20printing var foo=0; ) = 20 write(4, "var foo=0;\n", 11) = 11 write(2, "printing var bar=1;\n", 20printing var bar=1; ) = 20 write(4, "var bar=1;\n", 11) = 11 write(2, "printing var baz=3;\n", 20printing var baz=3; ) = 20 write(4, "var baz=3;\n", 11) = 11 read(3, "", 4096) = 0 close(3) = 0 write(2, "printing END\n", 13printing END ) = 13 write(4, "END\n", 4) = 4 close(4) = 0 close(5) = 0 wait4(8790, <unfinished ...>
      Perl's doing everything you ask of it. You're tracing the wrong program as far as I'm concerned.

        I'm not assuming any fault other than my own here. I have no problems with perl doing what I ask of it.

        What I'm trying to determine is whether I'm asking it to do things in the right order and in the right way to accomplish my goal.

        In other words, I'm trying to determine the nature of my fault. I know that I've made a mistake somewhere, either in lack of knowledge or improper approach. I know this because it doesn't work, but I'm trying to ensure that I'm doing everything right on the perl side and that my understanding is correct.

        I know that perl can interact with the interpreter and receive output from it.

        I know that the approach I'm trying to automate works from a terminal. I'm just trying to determine the disparity between the approach I'm taking on the terminal and my attempts to automate it so that I have a better idea of what's going on, and so that people having similar problems in the future might be able to learn from my mistakes.

      Call strace with the -f option to have it trace forked processes as well (i.e. the js interpreter).

      Comparing the output you get with what you get when doing the same steps interactively, would certainly help to figure out what's different. In particular look for the read(0, ...) calls from the subprocess.

        This appears to be the relevant output, but I'm not as familiar with strace as I'd like to be:

        mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, + 0) = 0xb7b8a000 read(0, "load(\'jslint.js\');\nfoo=0;\nEND\n", 1024) = 30 read(0, "", 1024) = 0 read(0, "", 1024) = 0 close(0) = 0 munmap(0xb7b8a000, 4096) = 0 brk(0x8092000) = 0x8092000 open("jslint.js", O_RDONLY) = 0 fstat64(0, {st_mode=S_IFREG|0644, st_size=147870, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, + 0) = 0xb7b8a000 read(0, "// (C)2002 Douglas Crockford\n// "..., 4096) = 4096 read(0, " \"lawngreen\": true,\n "..., 4096) = 4096 read(0, "iframe: {},\n img: {\n "..., 4096) = 4096 read(0, " convertPathToHFS: true,\n "..., 4096) = 4096 brk(0x80b3000) = 0x80b3000 read(0, "ption.safe) {\n if (op"..., 4096) = 4096 read(0, " errorAt(\"Expected \'{a}\' and in"..., 4096) = 4096 read(0, ", character + j);\n "..., 4096) = 4096 read(0, " }\n "..., 4096) = 4096 read(0, " line: line,\n "..., 4096) = 4096 read(0, " q += "..., 4096) = 4096 brk(0x80d4000) = 0x80d4000 read(0, " }\n "..., 4096) = 4096 read(0, " l += 1;\n "..., 4096) = 4096 read(0, " break;\n case \'/*jsl"..., 4096) = 4096 read(0, "efault:\n warning("..., 4096) = 4096 read(0, " x.nud = (typeof f === \'funct"..., 4096) = 4096 read(0, "n);\n nonadjacent(toke"..., 4096) = 4096 brk(0x80f5000) = 0x80f5000 read(0, "SAFE.go.\', nexttoken);\n "..., 4096) = 4096 read(0, " warning(\"Expec"..., 4096) = 4096 read(0, " warning(\"Expected a "..., 4096) = 4096 read(0, "rder-top-style\': cssBorderStyle,"..., 4096) = 4096 read(0, "\', \'hidden\', \'collapse\'],\n "..., 4096) = 4096 brk(0x8116000) = 0x8116000 read(0, "== \'important\') {\n "..., 4096) = 4096 read(0, " while (nexttoken.id !== \'</\'"..., 4096) = 4096 read(0, " if (option.adsafe && stack."..., 4096) = 4096 read(0, "f (nexttoken.id && nexttoken.id."..., 4096) = 4096 read(0, " if (t.name !== n) {\n "..., 4096) = 4096 read(0, " case \'label\':\n "..., 4096) = 4096 brk(0x8137000) = 0x8137000 read(0, "\');\n syntax[\'--\'].exps = true"..., 4096) = 4096 read(0, " advance(\'.\');\n "..., 4096) = 4096 read(0, "tation();\n }\n "..., 4096) = 4096 read(0, " }\n for (;;) {\n "..., 4096) = 4096 brk(0x8158000) = 0x8158000 read(0, "ance(\')\', t);\n nospace(pr"..., 4096) = 4096 read(0, "exttoken.id === \'var\') {\n "..., 4096) = 4096 read(0, "eserve(\'let\');\n reserve(\'supe"..., 4096) = 4096 read(0, " approved[option.approved["..., 4096) = 4096 read(0, " + (isFinite(c.line) ? \' at line"..., 4096) = 4096 brk(0x8179000) = 0x8179000 read(0, "ength; i += 1) {\n var"..., 4096) = 414 read(0, "", 4096) = 0 close(0) = 0 munmap(0xb7b8a000, 4096) = 0

        And if stops here until killed with ctrl-c, at which point it says "Process X detached", and I have to hunt down and kill the js process.

        I can see where it is receiving the output from the perl script:

        read(0, "load(\'jslint.js\');\nfoo=0;\nEND\n", 1024) = 30

        And the series of reads that begin with:

        read(0, "// (C)2002 Douglas Crockford\n// "..., 4096) = 4096

        Appears to be where it loads jslint.js from the disk in blocks, but then nothing else appears to happen, which is interesting. If I execute it from the command-line, this is the output (starting from the last read() from the source file:

        read(3, "ength; i += 1) {\n var"..., 4096) = 414 read(3, "", 4096) = 0 close(3) = 0 munmap(0xb7af6000, 4096) = 0 fstat64(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, + 0) = 0xb7af6000 read(0, foo=bar; "foo=bar;\n", 1024) = 9 read(0, END "END\n", 1024) = 4 write(1, "jslint: No problems found.\n", 27jslint: No problems found. ) = 27 write(1, "\n", 1 ) = 1 exit_group(3) = ?

        So, it displays "read(0" from the terminal. What is that telling me, precisely? Does this mean that, once it enters into the "input=readline();" loop, it sends the read signal when in a terminal, but not otherwise? If so, I guess that's my answer.