I'm using a pipe to communicate between two processes on Gnu/Linux. The receiving end closes the pipe while the sending end is still trying to send data. Here is some code that emulates the situation.
#include <unistd.h>
#include <boost/asio.hpp>
int main()
{
int pipe_fds[2];
if( ::pipe(pipe_fds) != 0 ) return 1;
// close the receiving end
::close( pipe_fds[0] );
boost::asio::io_service io;
boost::asio::posix::stream_descriptor sd( io, pipe_fds[1] );
boost::system::error_code ec;
sd.write_some( boost::asio::buffer("blah"), ec );
return 0;
}
When I run it I get a SIGPIPE; classic situation, I know. However, I see that boost::asio::error::basic_errors
has a broken_pipe
value. I would expect that to be returned in the error_code without a signal being raised.
Can this be done without creating a SIGPIPE handler for my process? For instance, is there a configuration option to boost::asio that I'm missing? Maybe something that would enable MSG_NOSIGNAL in the implementation?
Install a signal handler to ignore SIGPIPE
if you wish to see the appropriate error_code
code and compile
#include <unistd.h>
#include <iostream>
#include <boost/asio.hpp>
int main( int argc, const char** argv )
{
bool ignore = false;
if ( argc > 1 && !strcmp(argv[1], "ignore") ) {
ignore = true;
}
std::cout << (ignore ? "" : "not ") << "ignoring SIGPIPE" << std::endl;
if ( ignore ) {
struct sigaction sa;
std::memset( &sa, 0, sizeof(sa) );
sa.sa_handler = SIG_IGN;
int res = sigaction( SIGPIPE, &sa, NULL);
assert( res == 0 );
}
int pipe_fds[2];
if( ::pipe(pipe_fds) != 0 ) return 1;
// close the receiving end
::close( pipe_fds[0] );
boost::asio::io_service io;
boost::asio::posix::stream_descriptor sd( io, pipe_fds[1] );
boost::system::error_code ec;
sd.write_some( boost::asio::buffer("blah"), ec );
if ( ec ) {
std::cerr << boost::system::system_error(ec).what() << std::endl;
} else {
std::cout << "success" << std::endl;
}
return 0;
}
samjmill@bgqfen7 ~> g++ pipe.cc -lboost_system -lboost_thread-mt
samjmill@bgqfen7 ~>
run
samm@macmini ~> ./a.out
not ignoring SIGPIPE
samm@macmini ~> echo $?
141
samm@macmini ~> ./a.out ignore
ignoring SIGPIPE
Broken pipe
samm@macmini ~>
The rationale for this behavior is in the write(2)
man page
EPIPE
fd is connected to a pipe or socket whose reading end is closed. When this happens the writing process will also receive a SIGPIPE signal. (Thus, the write return value is seen only if the program catches, blocks or ignores this signal.)
emphasis added by me.
SIGPIPE is generated by the operating system when one end of a pipe is not connected - you can't really prevent it with boost::asio. You can however simply ignore the signal and the rest should take care of itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With