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.h 4.3 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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. #ifndef MINDSPORE_CCSRC_COMMON_DUPLEX_PIPE_H_
  17. #define MINDSPORE_CCSRC_COMMON_DUPLEX_PIPE_H_
  18. #include <unistd.h>
  19. #include <signal.h>
  20. #include <string>
  21. #include <memory>
  22. #include <initializer_list>
  23. #include <functional>
  24. #include "utils/log_adapter.h"
  25. #define DP_DEBUG MS_LOG(DEBUG) << "[DuplexPipe] "
  26. #define DP_INFO MS_LOG(INFO) << "[DuplexPipe] "
  27. #define DP_ERROR MS_LOG(ERROR) << "[DuplexPipe] "
  28. #define DP_EXCEPTION MS_LOG(EXCEPTION) << "[DuplexPipe] "
  29. namespace mindspore {
  30. // A tool to run a command as child process and build a duplex pipe between them.
  31. // Similar to 'popen()', but use duplex not simplex pipe, more like 'socketpair'.
  32. class DuplexPipe : public std::enable_shared_from_this<mindspore::DuplexPipe> {
  33. public:
  34. constexpr inline static int kBufferSize = 4096;
  35. constexpr inline static unsigned int kTimeOutSeconds = 5;
  36. DuplexPipe() = default;
  37. ~DuplexPipe() = default;
  38. // Create a subprocess and open a duplex pipe between local and remote
  39. int Open(std::initializer_list<std::string> arg_list, bool append_fds = false);
  40. void Close();
  41. void SetTimeOutSeconds(unsigned int secs) { time_out_secs_ = secs; }
  42. void SetTimeOutCallback(const std::shared_ptr<std::function<void()>> cb) { time_out_callback_ = cb; }
  43. void SetFinalizeCallback(const std::shared_ptr<std::function<void()>> cb) { finalize_callback_ = cb; }
  44. // Write the 'buf' to remote stdin
  45. void Write(const std::string &buf, bool flush = true);
  46. // Read from remote stdout/stderr into 'c_buf_'
  47. std::string Read();
  48. void WriteWithStdout(const std::string &buf, bool flush);
  49. std::string ReadWithStdin();
  50. DuplexPipe &operator<<(const std::string &buf);
  51. DuplexPipe &operator>>(std::string &buf);
  52. private:
  53. void SetTimeOut() {
  54. if (time_out_callback_ != nullptr && signal_handler_ != nullptr) {
  55. signal_handler_->SetAlarm(time_out_secs_);
  56. }
  57. }
  58. void CancelTimeOut() {
  59. if (time_out_callback_ != nullptr && signal_handler_ != nullptr) {
  60. signal_handler_->CancelAlarm();
  61. }
  62. }
  63. void NotifyTimeOut() {
  64. if (time_out_callback_ != nullptr) {
  65. (*time_out_callback_)();
  66. }
  67. Close();
  68. DP_EXCEPTION << "Time out when read from pipe";
  69. }
  70. void NotifyFinalize() {
  71. if (finalize_callback_ != nullptr) {
  72. (*finalize_callback_)();
  73. }
  74. }
  75. // Subprocess id in parent process,
  76. // otherwise zero in child process.
  77. pid_t pid_;
  78. // Pipe: { Local:fd1_[1] --> Remote:fd1_[0] }
  79. // Remote:fd1_[0] would be redirected by subprocess's stdin.
  80. // Local:fd1_[1] would be used by 'Write()' as output.
  81. int fd1_[2];
  82. // Pipe: { Remote:fd2_[1] --> Local:fd2_[0] }
  83. // Remote:fd2_[1] would be redirected by subprocess's stdout.
  84. // Local:fd2_[0] would be used by 'Read()' as input.
  85. int fd2_[2];
  86. // // Used and returned by 'Read()'.
  87. // std::string buf_;
  88. char c_buf_[kBufferSize];
  89. int local_stdin_;
  90. int local_stdout_;
  91. int remote_stdin_;
  92. int remote_stdout_;
  93. class SignalHandler {
  94. public:
  95. SignalHandler(std::shared_ptr<DuplexPipe> dp, pid_t pid);
  96. ~SignalHandler();
  97. void SetAlarm(unsigned int interval_secs);
  98. void CancelAlarm();
  99. private:
  100. static void SigAlarmHandler(int sig);
  101. static void SigPipeHandler(int sig);
  102. static void SigChildHandler(int sig);
  103. inline static std::shared_ptr<DuplexPipe> dp_;
  104. inline static pid_t child_pid_;
  105. };
  106. unsigned int time_out_secs_ = kTimeOutSeconds;
  107. std::shared_ptr<std::function<void()>> time_out_callback_;
  108. std::shared_ptr<std::function<void()>> finalize_callback_;
  109. std::shared_ptr<SignalHandler> signal_handler_;
  110. };
  111. } // namespace mindspore
  112. #endif // MINDSPORE_CCSRC_COMMON_DUPLEX_PIPE_H_