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.4 kB

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