You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

duplex_pipe.cc 4.5 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /**
  2. * Copyright 2020 Huawei Technologies Co., Ltd
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "common/duplex_pipe.h"
  17. #include <signal.h>
  18. #include <iostream>
  19. #include <vector>
  20. #include <algorithm>
  21. namespace mindspore {
  22. int DuplexPipe::Open(std::initializer_list<std::string> arg_list, bool append_fds) {
  23. if (pipe(fd1_) == -1) {
  24. DP_EXCEPTION << "pipe 1 failed, errno: " << errno;
  25. }
  26. if (pipe(fd2_) == -1) {
  27. close(fd1_[0]);
  28. close(fd1_[1]);
  29. DP_EXCEPTION << "pipe 2 failed, errno: " << errno;
  30. }
  31. pid_ = fork();
  32. if (pid_ < 0) {
  33. close(fd1_[0]);
  34. close(fd1_[1]);
  35. close(fd2_[0]);
  36. close(fd2_[1]);
  37. DP_EXCEPTION << "fork failed, errno: " << errno;
  38. } else if (pid_ == 0) { // Remote process
  39. DP_INFO << "Remote process, pid: " << getpid() << ", " << fd1_[0] << "/" << fd2_[1];
  40. remote_stdout_ = dup(STDOUT_FILENO);
  41. remote_stdin_ = dup(STDIN_FILENO);
  42. remote_stderr_ = dup(STDERR_FILENO);
  43. close(fd1_[1]);
  44. close(fd2_[0]);
  45. if (!append_fds) {
  46. dup2(fd1_[0], STDIN_FILENO);
  47. dup2(fd2_[1], STDOUT_FILENO);
  48. }
  49. std::vector<const char *> args;
  50. std::transform(arg_list.begin(), arg_list.end(), std::back_inserter(args),
  51. [](const std::string &arg) -> const char * { return arg.c_str(); });
  52. if (append_fds) {
  53. std::string fd10 = std::to_string(fd1_[0]).c_str();
  54. args.emplace_back(fd10.c_str());
  55. std::string fd21 = std::to_string(fd2_[1]).c_str();
  56. args.emplace_back(fd21.c_str());
  57. }
  58. args.emplace_back(nullptr);
  59. if (execvp(args[0], const_cast<char *const *>(&args[0])) == -1) {
  60. DP_EXCEPTION << "execute " << args[0] << " failed, errno: " << errno;
  61. }
  62. } else { // Local process
  63. DP_INFO << "Local process, id: " << getpid() << ", " << fd2_[0] << "/" << fd1_[1];
  64. local_stdout_ = dup(STDOUT_FILENO);
  65. local_stdin_ = dup(STDIN_FILENO);
  66. local_stderr_ = dup(STDERR_FILENO);
  67. close(fd1_[0]);
  68. close(fd2_[1]);
  69. }
  70. return 0;
  71. }
  72. void DuplexPipe::Write(const std::string &buf, bool flush) {
  73. // Write the string into pipe
  74. if (write(fd1_[1], buf.data(), buf.size()) == -1) {
  75. DP_ERROR << "write failed, errno: " << errno;
  76. return;
  77. }
  78. if (flush) {
  79. // Flush into the pipe
  80. if (write(fd1_[1], "\n", 1) == -1) {
  81. DP_ERROR << "write failed, errno: " << errno;
  82. return;
  83. }
  84. }
  85. DP_DEBUG << "<< [" << buf << "]";
  86. }
  87. std::string DuplexPipe::Read() {
  88. // Read the string from pipe
  89. std::string buf;
  90. ssize_t size;
  91. // MAYBE BLOCKED
  92. // Read one line or multiple lines
  93. while (SetTimeOut(), (size = read(fd2_[0], c_buf_, kBufferSize)) > 0) { // Till reading something
  94. CancelTimeOut();
  95. DP_DEBUG << ">> [" << c_buf_ << "]";
  96. bool line_end = c_buf_[size - 1] == '\n';
  97. buf.append(c_buf_, line_end ? size - 1 : size); // Copy without the last '\n'
  98. if (line_end) {
  99. break;
  100. }
  101. }
  102. return buf;
  103. }
  104. void DuplexPipe::WriteWithStdout(const std::string &buf, bool flush) {
  105. dup2(fd1_[1], STDOUT_FILENO);
  106. // Write the string into pipe
  107. std::cout << buf;
  108. if (flush) {
  109. // Flush into the pipe
  110. std::cout << std::endl;
  111. }
  112. dup2(local_stdout_, STDOUT_FILENO);
  113. }
  114. std::string DuplexPipe::ReadWithStdin() {
  115. std::string buf;
  116. dup2(fd2_[0], STDIN_FILENO);
  117. // Maybe blocked
  118. SetTimeOut();
  119. std::getline(std::cin, buf); // Not use 'std::cin >>' to include space
  120. CancelTimeOut();
  121. dup2(local_stdin_, STDIN_FILENO);
  122. return buf;
  123. }
  124. DuplexPipe &DuplexPipe::operator<<(const std::string &buf) {
  125. Write(buf);
  126. return *this;
  127. }
  128. DuplexPipe &DuplexPipe::operator>>(std::string &buf) {
  129. buf = Read();
  130. return *this;
  131. }
  132. void DuplexPipe::Close() {
  133. close(fd1_[0]);
  134. close(fd1_[1]);
  135. close(fd2_[0]);
  136. close(fd2_[1]);
  137. }
  138. void DuplexPipe::Alarm::Set(std::shared_ptr<DuplexPipe> dp, unsigned int interval_secs) {
  139. dp_ = dp;
  140. signal(SIGALRM, SigHandler);
  141. alarm(interval_secs);
  142. }
  143. void DuplexPipe::Alarm::Cancel() {
  144. alarm(0);
  145. dp_.reset();
  146. }
  147. } // namespace mindspore