[JAVA] Kinx Library --Process

Kinx Library --Process

Introduction

** "Looks like JavaScript, brain (contents) is Ruby, (stability is AC / DC)" ** Scripting language Kinx ). The library is the life of the language. So how to use the library.

This time it's Process. I hurriedly decided that it was necessary to start a child process.

System.exec()

A command execution interface that has been provided as standard for a long time. It's easy because it simply calls system () at the C level, but it's inconvenient because it doesn't come back until it finishes, or it can't get standard output. However, since the command is executed via the shell, redirects can be used.

So, this time I made a Process class that can do more things, so that is the favorite in this explanation.

Process

using Process

The Process library is not built-in as standard, so use the using directive to load it explicitly.

using Process;

Exec

Process object is created by new Process (command, opts). The argument is a command name and an array of arguments, or a command string. In the case of an array, it feels like passing arguments separately, and in the case of a command line character string, it is parsed internally and automatically decomposed into an array format.

The created process object has the following methods.

Method Overview
run() Start the process.
launch() Start and disconnect the process.
std() The option passed as an argument is returned.
{ in: opts.in, out: opts.out, err: opts.err }

Not running yet at this point. It starts when run () or launch () is performed. run () returns an object of the ProcessController class.

Run

run () returns an object of the ProcessController class.

var p = new Process(["cmd","arg1"]).run();

Launch

launch () returns nothing (or rather null). The method is to not take care of the child after pushing it out.

new Process(["cmd","arg1"]).launch();

ProcessController

The ProcessController class returned byrun ()has the following methods.

Method Overview
isAlive() True if the process is alive, if it has already ended, ordetachFalse after being done
wait() Waits for the process to end and returns the process exit code after the process ends.detachThen returns 0.
detach() Detach the process

detach () is detached after the process is started. On Linux, the behavior is slightly different from when it is separated by launch (), but what you want to do is the same. The internal operation is the same on Windows.

In Linux, the so-called ** double-fork ** method is used to disconnect at process startup, but this can only be used at process startup. It is virtually impossible to disconnect after starting a process, and the child will survive as a zombie unless it is properly wait or waitpid in the parent process.

So, at the moment of detach (), I start a thread just for waitpid and take care of it until the child dies.

By the way, double-fork is Linux,

By using the function called ..., you can fork the process once it was forked, then terminate the first forked process in haste and let init manage the grandchild process.

The top parent process remembers the waitpid of the first forked child. My grandchildren are the ones who take care of me.

Wait

The following is an example of waiting for the end and getting the end code.

var p = new Process(["cmd", "arg1"]).run();
var status = p.wait();

Of course, if you have detach, you cannot get it (0 is returned).

Detach

The detach that came out earlier. The process can also be detach. If you separate it, the connection with the child will be cut off. You don't have to wait and you don't have to worry about ending. Or rather, you can't do it even if you want to worry about it.

var p = new Process(["cmd", "arg1"]).run();
p.detach();

Pipe

I'm waiting for the pipe. The main purpose of creating Process is a pipe. The most desired function is to freely connect the standard input / output to the child process to a pipe to exchange information.

The pipe is specified by ʻoptsofnew Process (cmd, opts)`. There are three types of parameters as follows.

Parameters Contents
in Specify standard input.
You can specify a pipe object, a string,$stdin
out Specify standard output.
You can specify a pipe object, a string,$stdoutOr$stderr
err Specify standard error output.
You can specify a pipe object, a string,$stdoutOr$stderr

Pipe object

Create a pipe object with new Pipe (). Returns an array of two objects, [Read, Write], in pairs. The pipe object has the following methods.

Normally, the Write pipe is specified as ʻout or ʻerr of the child process to read from the Read pipe.

Read Pipe

Close the pipe after run (). Because it is set when run () is done.

Method
peek() Returns 0 if there is no data in the pipe, greater than 0 if there is.-1 is an error.
read() Get all pipe data as a character string. If there is no data, an empty string is returned.
close() Close the pipe.

Write Pipe

Close the pipe after run (). Because it is set when run () is done.

Method
write(data) Write data to the pipe. Not all can be written, and the number of bytes written is returned.
close() Close the pipe.
sample

The general form is used as follows.

using Process;

var [r1, w1] = new Pipe();
var p1 = new Process([ "ls", "-1" ], { out: w1 }).run();
w1.close(); //I don't use it anymore so you can close it
while (p1.isAlive() || r1.peek() > 0) {
    var buf = r1.read();
    if (buf.length() < 0) {
        System.println("Error...");
        return -1;
    } else if (buf.length() > 0) {
        System.print(buf);
    } else {
        // System.println("no input...");
    }
}
System.println("");

When using Write Pipe on the parent process side, it looks like this.

using Process;

//stdin reads from pipe and outputs to standard output
[r1, w1] = new Pipe();
var p1 = new Process("cat", { in: r1, out: $stdout }).run();
r1.close(); //I don't use it anymore so you can close it

//Send to stdin on p1
var nwrite = w1.write("Message\n");
w1.close(); //Pipe close, transmission end

p1.wait();

By the way, you can control standard output and standard error output.

new Process("cmd", { out: $stdout, err: $stdout }); //Merge standard error output with standard output
new Process("cmd", { out: $stderr, err: $stderr }); //Merge standard output with standard error output
new Process("cmd", { out: $stderr, err: $stdout }); //Swap

Pipeline

Connecting pipes is quite a tedious task (or rather, which one is ...?), So I also defined Process.pipeline, which does it all at once. Finally, put a callback function and use it as follows.

var r = Process.pipeline(cmd1, cmd2, cmd3, ..., &(i, o, pipeline) => {
    // i ...Write pipe to stdin for the first command
    // o ...Read pipe from stdout of last command
    // pipeline ...Pipeline object
    //    pipeline.input .......Same as i above
    //    pipeline.output ......Same as o above
    //    pipeline.peek() ...... pipeline.output.peek()Same as
    //    pipeline.read() ...... pipeline.output.read()Same as
    //    pipeline.write() ..... pipeline.input.write()Same as
    //    pipeline.isAlive() ...True if any process in the pipeline is alive
    //    pipeline.wait() ......Wait for all the processes in the pipeline to complete,
    //Returns an exit code as an array

    //Callback return value remains Process.pipeline()It becomes the return value of.
    return pipeline.wait();
});

You can use it without calling back.

var pipeline = Process.pipeline(cmd1, cmd2, cmd3, ...);
// pipeline ...Pipeline object
//Omitted below.

in conclusion

The child process relationship is different between Windows and Linux, so it is a good point of the script to be able to handle such things in a unified manner. However, the commands themselves are different, so it's hard to absorb them. I'm a Windows user, but I use UnxUtils to make some Unix commands available at the command prompt. (I don't really like Cygwin because it changes the environment ...)

So, next time.

Recommended Posts

Kinx Library --Process
Kinx Library --Getopt
Kinx Library-JIT Compiler Library
Kinx Library-JIT Compiler Library (Extra Edition)