How to bind program termination with end-of-stream in Boost.Process 0.5?

Hi, I have a simple question about the latest Boost.Process 0.5 library. Namely how to How to bind program termination with end-of-stream in Boost.Process 0.5? For example, in this example http://www.highscore.de/boost/process0.5/boost_process/tutorial.html#boost_p... One can make a look to read the output of the process until the program finishes, but the stream is not invalid after program termination. ... while(std::getline(is, s)){ // is is an stream associated with a process (e.g. '/usr/bin/ls') std::cout << "read: " << s << std::endl; } std::clog << "end" << std::endl; // never reach ... I originally posted the question in http://stackoverflow.com/questions/12329065/how-to-bind-program-termination-... but now I think it can be overlooked there. Since now there seems to be extra layers (Boost.Streams) it may be that I don't know how to set up the file_descriptor_source, etc. BTW, the solution to this question can be used to improve the example code in http://www.highscore.de/boost/process0.5/boost_process/tutorial.html Thanks, Alfredo -- View this message in context: http://boost.2283326.n4.nabble.com/How-to-bind-program-termination-with-end-... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Sun, 09 Sep 2012 02:00:06 +0200, alfC <alfredo.correa@gmail.com> wrote: Hi Alfredo, thanks for your question! Good to see that people start using the new version. :)
Is "is" a Boost.Iostreams stream? If so, do you use Boost 1.50.0 or an earlier version? Then I strongly recommend upgrading to Boost 1.51.0. Various end-of-stream unit tests failed when I used Boost 1.50.0 because of a bug in Boost.Iostreams. HTH, Boris
[...]

On Wed, Sep 12, 2012 at 12:12 PM, Boris Schaeling [via Boost] <ml-node+s2283326n4635662h0@n4.nabble.com> wrote:
no, thanks to you for the library. I have a small criticism (probably from ignorance) and it is that the new version seems to be more complicated to use than the previous versions.
"is" is a boost::iostreams::stream<file_descriptor_source>, like in the examples, do I have another option? (e.g. to simplify the number of layers) The full example that does not work for me is this, message continues below: #include <boost/process.hpp> // version 0.5 from http://www.highscore.de/boost/process0.5/process.zip #include <boost/iostreams/device/file_descriptor.hpp> #include <boost/iostreams/stream.hpp> #include <string> using namespace boost::process; using namespace boost::process::initializers; using namespace boost::iostreams; int main(){ boost::process::pipe p = create_pipe(); file_descriptor_sink sink(p.sink, close_handle); child c = execute(run_exe("/usr/bin/ls"), bind_stdout(sink)); file_descriptor_source source(p.source, close_handle); stream<file_descriptor_source> is(source); std::string s; while(std::getline(is, s)){ std::cout << "read: " << s << std::endl; } std::clog << "end" << std::endl; // never reach } If so, do you use Boost 1.50.0 or an
earlier version? Then I strongly recommend upgrading to Boost 1.51.0.
actually I am using 1.48 (default in fedora 17).
Various end-of-stream unit tests failed when I used Boost 1.50.0 because of a bug in Boost.Iostreams.
If that is the case you can add a warning in the library to not compile with old versions of boost. someone at stackoverflow, suggested to open the process asynchronously and do a status check. (see http://stackoverflow.com/questions/12329065/how-to-bind-program-termination-...) Seemed like an ovekill. I am glad it is a bug instead. Thank you very much. Alfredo -- View this message in context: http://boost.2283326.n4.nabble.com/How-to-bind-program-termination-with-end-... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Wed, 12 Sep 2012 22:10:12 +0200, alfC <alfredo.correa@gmail.com> wrote:
Oh, do you have an example for me to see where you think the new version is more complicated than the previous one?
There is actually a note at <http://www.highscore.de/boost/process0.5/boost_process/tutorial.html#boost_process.tutorial.synchronous_i_o> to inform users about that bug in Boost.Iostreams. Maybe it shouldn't be a note but a warning or something else which can't be overlooked easily? :) Boris
[...]

On Sat, Sep 15, 2012 at 8:46 AM, Boris Schaeling [via Boost] <ml-node+s2283326n4635808h26@n4.nabble.com> wrote:
Well, in the first place: the added dependecy on boost.iostreams which I was not familiar with. Which in addition is not a header-only library. Second, in the example code, there are four lines (marked with *) just to set up the stream, * boost::process::pipe p = create_pipe(); * file_descriptor_sink sink(p.sink, close_handle); child c = execute(run_exe("/usr/bin/ls"), bind_stdout(sink)); * file_descriptor_source source(p.source, close_handle); * stream<file_descriptor_source> is(source); if I were to have an output stream I would need four more lines presumably (I would be nice to have a complete example of asynchonic both input and output). So, the question is, is the boost.iostream really necessary? or is shown in the example for generality? Even if boost.iostream lines are necessary, can they be that wrapped away (by the user), or the library, such that you have something that just works? For example: process::iostream ps("/usr/bin/ls"); // or as a function auto ps = process::create_iostream("/usr/bin/ls"); // bang!, ps is ready for io operations,
ah, you are talking about that note, well the note says: "There is a Boost.Iostreams bug on Windows...", but all these issues are in Linux. I want to write a note in stackoverflow, can you confirm that the problem was a bug in Boost.Iostream in linux/posix also? Thanks, Alfredo -- View this message in context: http://boost.2283326.n4.nabble.com/How-to-bind-program-termination-with-end-... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Sat, 15 Sep 2012 21:36:53 +0200, alfC <alfredo.correa@gmail.com> wrote:
[...]So, the question is, is the boost.iostream really necessary? or is shown in the example for generality?
Boost.Process uses the types file_descriptor_source and file_descriptor_sink from Boost.Iostreams to wrap a file descriptor or Windows handle. For example, the initializers bind_stdin, bind_stdout and bind_stderr expect a file_descriptor_source or file_descriptor_sink to get a file descriptor or Windows handle which is then redirected and passed to the child process. I could extend those initializers though so that you could pass a file descriptor or Windows handle directly (without wrapping it in a Boost.Iostreams type)?
Hm, the bug in Boost.Iostreams was a Windows-only bug. I didn't experience any problems with any of the library's unit tests on Linux. Boris
[...]

On Sat, Sep 15, 2012 at 5:05 PM, Boris Schaeling [via Boost] <ml-node+s2283326n4635818h36@n4.nabble.com> wrote:
ok, thanks for the info. Is that a question for me? I am not familiar with these objects. Also I use Linux only for development. These objects didn't seem to be necessary in Boost.Process GSOC2010.
ok, since there is no conclusive solution, so maybe to end this thread let me file this as a possible bug (or confirm it is the expected behavior), the symptom is that the program never ends (linux, fedora 17, boost 1.48): #include <boost/process.hpp> // version 0.5 from http://www.highscore.de/boost/process0.5/process.zip #include <boost/iostreams/device/file_descriptor.hpp> #include <boost/iostreams/stream.hpp> #include <string> using namespace boost::process; using namespace boost::process::initializers; using namespace boost::iostreams; int main(){ boost::process::pipe p = create_pipe(); file_descriptor_sink sink(p.sink, close_handle); child c = execute(run_exe("/usr/bin/ls"), bind_stdout(sink)); file_descriptor_source source(p.source, close_handle); stream<file_descriptor_source> is(source); std::string s; while(std::getline(is, s)){ std::cout << "read: " << s << std::endl; } std::clog << "end" << std::endl; // never reach } -- View this message in context: http://boost.2283326.n4.nabble.com/How-to-bind-program-termination-with-end-... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Sun, 16 Sep 2012 05:29:29 +0200, alfC <alfredo.correa@gmail.com> wrote:
That's true (I see you are familiar with previous versions :). We had a handle type which was defined by Boost.Process. We also had stream types like pistream and postream. All of this has been replaced with types from Boost.Iostreams. We could still define all of this in Boost.Process theoretically. But I think it makes more sense if we reuse other Boost libraries and concentrate in Boost.Process on what that library really is about (especially after working on it for six years ;).
Can you try this program? It works for me: ----- #include <boost/process.hpp> #include <boost/iostreams/device/file_descriptor.hpp> #include <boost/iostreams/stream.hpp> #include <string> using namespace boost::process; using namespace boost::process::initializers; using namespace boost::iostreams; int main() { boost::process::pipe p = create_pipe(); { file_descriptor_sink sink(p.sink, close_handle); execute(run_exe("/bin/ls"), bind_stdout(sink)); } file_descriptor_source source(p.source, close_handle); stream<file_descriptor_source> is(source); std::string s; while(std::getline(is, s)){ std::cout << "read: " << s << std::endl; } std::clog << "end" << std::endl; } ----- Boris
[...]

On Sun, Sep 16, 2012 at 11:54 AM, Boris Schaeling [via Boost] <ml-node+s2283326n4635834h32@n4.nabble.com> wrote:
I guess it is not not late to provide "convenience" pistream/postream/piostream classes that wrap up all the complexity. boost::pistream pis("/bin/ls"); for(std::string line; std::getline(pis, line); ){ std::cout << "line: " << line << std::endl; } std::cout << "end" << std::endl;
Thanks, the program worked (boost 1.48) and I posted the solution in stakoverflow: http://stackoverflow.com/a/12469478/225186 I don't have any idea why this works vs. the other. I wonder if I have to do the same for doing output to the process. Thanks, Alfredo
-- Alfredo -- View this message in context: http://boost.2283326.n4.nabble.com/How-to-bind-program-termination-with-end-... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Tue, 18 Sep 2012 04:29:37 +0200, alfC <alfredo.correa@gmail.com> wrote:
It's required to close the write-end of the pipe also in the parent process. The child process inherits the write-end and closes it. But it really closes only a copy. Once the file_descriptor_sink initialized with close_handle goes out of the scope, the write-end in the parent process is closed, too. HTH, Boris
[...]

Hi Boris, Thank you very much for your help. See below for proposed code for your library. On Mon, Sep 17, 2012 at 7:29 PM, Alfredo Correa <alfredo.correa@gmail.com> wrote:
If you don't mind, let me propose the following wrapper class for the casual user. I had to play a little bit with protected inheritance to make it work. I remember other cases where protected inheritance was necessary in order to define derived stream classes. I kept it simple to communicate the idea, I guess more template const Initializer& can be passed through the constructor. An equivalent one can be made for postream, and even piostream. // ... // Copyright (c) 2012 Alfredo Correa // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) /** * \file boost/process/pistream.hpp * * Convenience pistream class prototype */ #include <boost/process.hpp> // version 0.5 #include <boost/iostreams/device/file_descriptor.hpp> #include <boost/iostreams/stream.hpp> #include <string> namespace boost{ namespace process{ class pistream : protected pipe, protected iostreams::file_descriptor_source, public iostreams::stream<boost::iostreams::file_descriptor_source>{ public: pistream(const std::string& cmd) : pipe(create_pipe()), file_descriptor_source(this->source, iostreams::close_handle), stream<file_descriptor_source>((file_descriptor_source&)(*this)){ execute( initializers::run_exe(cmd), initializers::bind_stdout(iostreams::file_descriptor_sink(this->sink, iostreams::close_handle)) ); } }; }} // example code int main(){ boost::process::pistream pis("/usr/bin/ls"); std::string s; while(std::getline(pis, s)){ std::cout << "read: " << s << std::endl; } } Thanks, Alfredo
-- Alfredo -- View this message in context: http://boost.2283326.n4.nabble.com/How-to-bind-program-termination-with-end-... Sent from the Boost - Dev mailing list archive at Nabble.com.
participants (2)
-
alfC
-
Boris Schaeling