| 1364 | } |
| 1365 | |
| 1366 | inline std::pair<OutBuffer, ErrBuffer> |
| 1367 | Communication::communicate(const char* msg, size_t length) |
| 1368 | { |
| 1369 | // Optimization from subprocess.py |
| 1370 | // If we are using one pipe, or no pipe |
| 1371 | // at all, using select() or threads is unnecessary. |
| 1372 | auto hndls = {stream_->input(), stream_->output(), stream_->error()}; |
| 1373 | int count = std::count(std::begin(hndls), std::end(hndls), nullptr); |
| 1374 | const int len_conv = length; |
| 1375 | |
| 1376 | if (count >= 2) { |
| 1377 | OutBuffer obuf; |
| 1378 | ErrBuffer ebuf; |
| 1379 | if (stream_->input()) { |
| 1380 | if (msg) { |
| 1381 | int wbytes = std::fwrite(msg, sizeof(char), length, stream_->input()); |
| 1382 | if (wbytes < len_conv) { |
| 1383 | if (errno != EPIPE && errno != EINVAL) { |
| 1384 | throw OSError("fwrite error", errno); |
| 1385 | } |
| 1386 | } |
| 1387 | } |
| 1388 | // Close the input stream |
| 1389 | stream_->input_.reset(); |
| 1390 | } else if (stream_->output()) { |
| 1391 | // Read till EOF |
| 1392 | // ATTN: This could be blocking, if the process |
| 1393 | // at the other end screws up, we get screwed as well |
| 1394 | obuf.add_cap(out_buf_cap_); |
| 1395 | |
| 1396 | int rbytes = util::read_all( |
| 1397 | stream_->output(), |
| 1398 | obuf.buf); |
| 1399 | |
| 1400 | if (rbytes == -1) { |
| 1401 | throw OSError("read to obuf failed", errno); |
| 1402 | } |
| 1403 | |
| 1404 | obuf.length = rbytes; |
| 1405 | // Close the output stream |
| 1406 | stream_->output_.reset(); |
| 1407 | |
| 1408 | } else if (stream_->error()) { |
| 1409 | // Same screwness applies here as well |
| 1410 | ebuf.add_cap(err_buf_cap_); |
| 1411 | |
| 1412 | int rbytes = util::read_atmost_n( |
| 1413 | stream_->error(), |
| 1414 | ebuf.buf.data(), |
| 1415 | ebuf.buf.size()); |
| 1416 | |
| 1417 | if (rbytes == -1) { |
| 1418 | throw OSError("read to ebuf failed", errno); |
| 1419 | } |
| 1420 | |
| 1421 | ebuf.length = rbytes; |
| 1422 | // Close the error stream |
| 1423 | stream_->error_.reset(); |