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();
  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. // Pipe: { Local:fd1_[1] --> Remote:fd1_[0] }
  76. // Remote:fd1_[0] would be redirected by subprocess's stdin.
  77. // Local:fd1_[1] would be used by 'Write()' as output.
  78. int fd1_[2];
  79. // Pipe: { Remote:fd2_[1] --> Local:fd2_[0] }
  80. // Remote:fd2_[1] would be redirected by subprocess's stdout.
  81. // Local:fd2_[0] would be used by 'Read()' as input.
  82. int fd2_[2];
  83. // // Used and returned by 'Read()'.
  84. // std::string buf_;
  85. char c_buf_[kBufferSize];
  86. int local_stdin_;
  87. int local_stdout_;
  88. int remote_stdin_;
  89. int remote_stdout_;
  90. class SignalHandler {
  91. public:
  92. SignalHandler(const std::weak_ptr<DuplexPipe> &dp, pid_t *pid);
  93. ~SignalHandler();
  94. void SetAlarm(unsigned int interval_secs);
  95. void CancelAlarm();
  96. private:
  97. static void SigAlarmHandler(int sig);
  98. static void SigPipeHandler(int sig);
  99. static void SigChildHandler(int sig);
  100. inline static std::weak_ptr<DuplexPipe> dp_;
  101. inline static pid_t *child_pid_;
  102. };
  103. unsigned int time_out_secs_ = kTimeOutSeconds;
  104. std::shared_ptr<std::function<void()>> time_out_callback_;
  105. std::shared_ptr<std::function<void()>> finalize_callback_;
  106. // signal_handler_ has a pid_ pointer, so it must be ahead of pid_
  107. std::shared_ptr<SignalHandler> signal_handler_;
  108. // Subprocess id in parent process,
  109. // otherwise zero in child process.
  110. pid_t pid_;
  111. };
  112. } // namespace mindspore
  113. #endif // MINDSPORE_CCSRC_COMMON_DUPLEX_PIPE_H_