1995parham / Loole

Linux pipes (Named-UnNamed) binding for node.js
GNU General Public License v3.0
2 stars 0 forks source link

Process hangs because of unclosed unnamed pipe. #1

Open aa6 opened 7 years ago

aa6 commented 7 years ago

Everything runs perfectly except one thing: pipe's output stream doesn't get closed when pipe's input stream is closed. And that causes the program to run forever until it's closed manually by Ctrl+C. Probably the module must watch for input to close and then close the output but I'm not sure because calling dev_fd_pipe_out.close() on dev_fd_pipe_in closing doesn't helps the situation.

[ fs, loole, child_process ] = [
    require("fs"), require("loole"), require("child_process")
]

loole.createPipe().then(function(fds)
{
    var cp1 = child_process.spawn('echo', ['TEST','STRING'])
    var dev_fd_pipe_in = fs.createWriteStream(`/dev/fd/${fds[1]}`)
    var dev_fd_pipe_out = fs.createReadStream(`/dev/fd/${fds[0]}`)
    cp1.stdout.pipe(dev_fd_pipe_in)
    dev_fd_pipe_out.pipe(process.stdout)

    cp1.stdout.on("close",function()
    {
        console.log("cp1.stdout closed")
    })
    dev_fd_pipe_in.on("close",function()
    {
        console.log("dev_fd_pipe_in closed")
    })
    dev_fd_pipe_out.on("close",function()
    {
        console.log("dev_fd_pipe_out closed")
    })
    process.stdout.on("close",function()
    {
        console.log("process.stdout closed")
    })
})

Prints:

$ node 3.js 
cp1.stdout closed
TEST STRING
dev_fd_pipe_in closed
^C
1995parham commented 7 years ago

Thanks for reporting and sorry for taking too much to complete this module, I will to my best to correct this bug.

aa6 commented 7 years ago

I'm sorry too for not having enough knowledge to help you fix the bug.

1995parham commented 7 years ago

I don't know why but this version of your code is working:

[ fs, loole, child_process ] = [
    require("fs"), require("loole"), require("child_process")
]

loole.createPipe().then(function(fds)
{
    var cp1 = child_process.spawn('echo', ['TEST','STRING'])
    var dev_fd_pipe_in = fs.createWriteStream('', {fd: fds[1]})
    var dev_fd_pipe_out = fs.createReadStream(`/dev/fd/${fds[0]}`)
    cp1.stdout.pipe(dev_fd_pipe_in)
    dev_fd_pipe_out.pipe(process.stdout)

    cp1.stdout.on("close",function()
    {
        console.log("cp1.stdout closed")
    })
    dev_fd_pipe_in.on("close",function()
    {
        console.log("dev_fd_pipe_in closed")
    })
    dev_fd_pipe_out.on("close",function()
    {
        console.log("dev_fd_pipe_out closed")
    })
    process.stdout.on("close",function()
    {
        console.log("process.stdout closed")
    })
})
aa6 commented 7 years ago

Doesn't seems to work in conjunction with 1.js and 2.js 1.js:

process.stdout.write("Hello world.\n")

2.js:

console.log(process.argv)
process.stdout.write(
    require("fs")
    .readFileSync(process.argv[2])
    .toString()
    .replace(/Hello/,"Goodbye")
)

3.js:

[ fs, loole, child_process ] = [
    require("fs"), require("loole"), require("child_process")
]

loole.createPipe().then(function(fds)
{
    var child_process = require("child_process")
    var cp1 = child_process.spawn("node",[__dirname + "/1.js"])
    var dev_fd_pipe_in = fs.createWriteStream('', {fd: fds[1]})
    cp1.stdout.pipe(dev_fd_pipe_in)
    var cp2 = child_process.spawn("node",[__dirname + "/2.js",`/dev/fd/${fds[0]}`])
    cp2.stdout.pipe(process.stdout)
})

Could it be somehow interconnected with my other question about file descriptors? https://stackoverflow.com/questions/26561938/what-are-these-file-descriptors-for Because if I run an fds.js:

fs = require('fs')

for(var i = 0; i < 1000; i++)
{
    console.log(i,fs.fstatSync(i).size)
}

I get the next output:

$ node fds.js 
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
fs.js:896
  return binding.fstat(fd);
                 ^

Error: EBADF: bad file descriptor, fstat
    at Object.fs.fstatSync (fs.js:896:18)
    at Object.<anonymous> (/home/me/tst/subst/fds.js:5:22)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.runMain (module.js:605:10)
    at run (bootstrap_node.js:420:7)
    at startup (bootstrap_node.js:139:9)

it shows that fds from 0 to 11 are already open and 3.js gives to 2.js /dev/fd/9 as an argument

$ node 3.js 
[ '/home/me/.nvm/versions/node/v7.2.0/bin/node',
  '/home/me/tst/subst/2.js',
  '/dev/fd/9' ]
^C

but when I run 2.js within bash, I get an fd no lesser than 63.

$ node 2.js <(<<<"Hello")
[ '/home/me/.nvm/versions/node/v7.2.0/bin/node',
  '/home/me/tst/subst/2.js',
  '/dev/fd/63' ]

Could it be that node engine abuses some internal mechanisms of file descriptors allocation and just grabs first eleven wihout any permission for it's own internal purposes?