[pipe_open(-ReadPipe, -WritePipe)]
Open a new pipe and return the read end and the write end of that
pipe. If the operation fails, both ReadPipe and WritePipe
are bound to negative numbers.
The pipes returned by the pipe_open/2 predicate are small
integers that represent file descriptors used by the underlying
OS. They are not XSB I/O streams, and they cannot be used for
I/O directly. To use them, one must convert them to streams using open/3 or open/4. 1.7
The best way to illustrate how one can create a new pipe to a child (even if the child has been created earlier) is to show an example. Consider two programs, parent.P and child.P. The parent copy of XSB consults parent.P, which does the following: First, it creates a pipe and spawns a copy of XSB. Then it tells the child copy of XSB to assert the fact pipe(RP), where RP is a number representing the read part of the pipe. Next, the parent XSB tells the child XSB to consult the program child.P. Finally, it sends the message Hello!.
The child.P program gets the pipe from predicate pipe/1 (note that the parent tells the child XSB to first assert pipe(RP) and only then to consult the child.P file). After that, the child reads a message from the pipe and prints it to its standard output. Both programs are shown below:
%% parent.P :- import pipe_open/2 from file_io. %% Create the pipe and pass it to the child process ?- pipe_open(RP,WP), %% WF is now the XSB I/O stream bound to the write part of the pipe open(pipe(WP),write,WF), %% ProcInput becomes the XSB stream leading directly to the child's stdin spawn_process(nxsb1, ProcInput, block, block, Process), %% Tell the child where the reading part of the pipe is fmt_write(ProcInput, "assert(pipe(%d)).\n", arg(RP)), fmt_write(ProcInput, "[child].\n", _), flush_output(ProcInput, _), %% Pass a message through the pipe fmt_write(WF, "Hello!\n", _), flush_output(WF, _), fmt_write(ProcInput, "end_of_file.\n",_), % send end_of_file atom to child flush_output(ProcInput, _), %% wait for child (so as to not leave zombies around; %% zombies quit when the parent finishes, but they consume resources) process_control(Process, wait), %% Close the ports used to commuicate with the process %% Otherwise, the parent might run out of file descriptors %% (if many processes were spawned) close(ProcInput), close(WF).
%% child.P
:- import file_read_line_atom/2 from file_io.
:- dynamic pipe/1.
?- pipe(P), open(pipe(P),read,F),
%% Acknowledge receipt of the pipe
fmt_write("\nPipe %d received\n", arg(P)),
%% Get a message from the parent and print it to stdout
file_read_line_atom(F, Line), write('Message was: '), writeln(Line).
This produces the following output:
| ?- [parent]. <- parent XSB consults parent.P [parent loaded] yes | ?- [xsb_configuration loaded] <- parent.P spawns a child copy of XSB [sysinitrc loaded] Here we see the startup messages of [packaging loaded] the child copy XSB Version 2.0 (Gouden Carolus) of June 27, 1999 [i686-pc-linux-gnu; mode: optimal; engine: slg-wam; scheduling: batched] | ?- yes | ?- [Compiling ./child] <- The child copy of received the pipe from [child compiled, cpu time used: 0.1300 seconds] the parent and then the [child loaded] request to consult child.P Pipe 15 received <- child.P acknowledges receipt of the pipe Message was: Hello! <- child.P gets the message and prints it yes
Observe that the parent process is very careful about making sure that the child terminates and also about closing the I/O streams after they are no longer needed.
Finally, we should note that this mechanism can be used to communicate through pipes with non-XSB processes as well. Indeed, an XSB process can create a pipe using pipe_open (before spawning a child process), pass one end of the pipe to a child process (which can be a C program), and use open/3 to convert the other end of the pipe to an XSB stream. The C program, of course, does not need open/3, since it can use the pipe file handle directly. Likewise, a C program can spawn off an XSB process and pass it one end of a pipe. The XSB child-process can then convert this pipe fd to a file using fd2iostream and then talk to the parent C program.
[fd2iostream(+Pipe, -IOstream)]
Take a file descriptor and convert it to an XSB I/O stream. This
predicate should be used only for user-defined I/O. Otherwise, use
open/{3,4} when possible.