The new std.process is ready for review

Steven Schveighoffer schveiguy at yahoo.com
Wed Mar 6 08:45:54 PST 2013


On Tue, 05 Mar 2013 17:38:09 -0500, Vladimir Panteleev  
<vladimir at thecybershadow.net> wrote:

> On Tuesday, 5 March 2013 at 21:55:24 UTC, Steven Schveighoffer wrote:
>> On Tue, 05 Mar 2013 16:04:14 -0500, Vladimir Panteleev  
>> <vladimir at thecybershadow.net> wrote:
>>
>>> 4. Is there any way to deal with pipe clogging (pipe buffer getting  
>>> exceeded when manually handling both input and output of a  
>>> subprocess)? Can we query the number of bytes we can immediately  
>>> read/write without blocking on a File?
>>
>> I don't know how this could happen, can you elaborate?  Perhaps an  
>> example?
>
> OK! Here's a program based off the pipeProcess/pipeShell example:
>
> ---
> import std.file;
> import std.process2;
> import std.stdio;
> import std.string;
>
> void main()
> {
>      auto pipes = pipeProcess("./my_application",
>          Redirect.stdout | Redirect.stderr);
>      scope(exit) wait(pipes.pid);
>
>      // Store lines of output.
>      string[] output;
>      foreach (line; pipes.stdout.byLine) output ~= line.idup;
>
>      // Store lines of errors.
>      string[] errors;
>      foreach (line; pipes.stderr.byLine) errors ~= line.idup;
>
>      writefln("%d lines of stdout, %d lines of stderr",
>          output.length, errors.length);
> }
> ---
>
> And here is an accompanying my_application.d:
>
> ---
> import std.stdio;
>
> enum N = 100;
>
> void main()
> {
>      foreach (n; 0..N)
>      {
>          stdout.writeln("stdout");
>          stderr.writeln("stderr");
>      }
> }
> ---
>
> Now, everything works just fine when N is small. However, if you  
> increase it to 10000, both the test program and my_application get stuck  
> with 0% CPU usage.
>
> The reason for that is that the stderr pipe is clogged: my_application  
> can't write to it, because nothing is reading from the other end. At the  
> same time, the first program is blocked on reading from the stdout pipe,  
> but nothing is coming out, because my_application is blocked on writing  
> to stderr.

Right, the issue there is, File does not make a good socket/pipe  
interface.  I don't know what to do about that.

a while ago (2008 or 09 I believe?), I was using Tango's Process object to  
execute programs on a remote agent, and forwarding all the resulting data  
back over the network.  On Linux, I used select to read data as it  
arrived.  On Windows, I think I had to spawn off a separate thread to wait  
for data/child processes.

But Tango did not base it's I/O on FILE *, so I think we had more  
flexibility there.

Suggestions are welcome...

>
> By the way, I should mention that I ran into several issues while trying  
> to come up with the above example. The test program does not work on  
> Windows, for some reason I get the exception:
>
> std.process2.ProcessException at std\process2.d(494): Failed to spawn new  
> process (The parameter is incorrect.)

I think Lars is on that.

>
> I've also initially tried writing a different program:
>
> ---
> import std.file;
> import std.process2;
> import std.string;
>
> /// Sort an array of strings using the Unix "sort" program.
> string[] unixSort(string[] lines)
> {
> 	auto pipes = pipeProcess("sort", Redirect.stdin | Redirect.stdout);
> 	scope(exit) wait(pipes.pid);
>
> 	foreach (line; lines)
> 		pipes.stdin.writeln(line);
> 	pipes.stdin.close();
>
> 	string[] sortedLines;
> 	foreach (line; pipes.stdout.byLine())
> 		sortedLines ~= line.idup;
>
> 	return sortedLines;
> }
>
> void main()
> {
> 	// For the sake of example, pretend these lines came from
> 	// some intensive computation, and not actually a file.
> 	auto lines = readText("input.txt").splitLines();
>
> 	auto sortedLines = unixSort(lines);
> }
> ---
>
> However, I couldn't get it to work neither on Windows (same exception)  
> nor Linux (it just gets stuck, even with a very small input.txt). No  
> idea if I'm doing something wrong (maybe I need to indicate EOF in some  
> way?) or if the problem is elsewhere.

Linux should work here.  From what I can tell, you are doing it right.

If I get some time, I'll try and debug this.

>
>> We are sort of stuck with File being the stream handler in phobos,  
>> which means we are currently stuck with FILE *.  I don't know if there  
>> is a way to do partial reads/writes on a FILE *, or checking to see if  
>> data is available.
>
> I guess you could always get the OS file handles/descriptors and query  
> them directly, although there's also the matter of the internal FILE *  
> buffers.

I think at that point, you would have to forgo all usage of File niceties  
(writeln, etc).  Which would really suck.

But on the read end, this is a very viable option.

-Steve


More information about the Digitalmars-d mailing list