ProcessPosix.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Util/Process.h>
  6. #include <AnKi/Util/Functions.h>
  7. #include <sys/wait.h>
  8. #include <fcntl.h>
  9. #include <errno.h>
  10. #include <unistd.h>
  11. namespace anki {
  12. Process::~Process()
  13. {
  14. ProcessStatus s;
  15. const Error err = getStatus(s);
  16. if(err)
  17. {
  18. ANKI_UTIL_LOGE("Failed to get the status. Expect cleanup errors");
  19. return;
  20. }
  21. if(s == ProcessStatus::RUNNING)
  22. {
  23. ANKI_UTIL_LOGE("Destroying while child process is running");
  24. return;
  25. }
  26. destroyPipes();
  27. }
  28. void Process::destroyPipes()
  29. {
  30. for(U32 i = 0; i < 2; ++i)
  31. {
  32. close(m_stdoutPipe[i]);
  33. close(m_stderrPipe[i]);
  34. m_stdoutPipe[i] = m_stderrPipe[i] = -1;
  35. }
  36. }
  37. Error Process::createPipes()
  38. {
  39. destroyPipes();
  40. if(pipe(m_stdoutPipe.getBegin()) || pipe(m_stderrPipe.getBegin()))
  41. {
  42. ANKI_UTIL_LOGE("pipe() failed: %s", strerror(errno));
  43. return Error::FUNCTION_FAILED;
  44. }
  45. fcntl(m_stdoutPipe[0], F_SETFL, O_NONBLOCK);
  46. fcntl(m_stderrPipe[0], F_SETFL, O_NONBLOCK);
  47. return Error::NONE;
  48. }
  49. Error Process::start(CString executable, ConstWeakArray<CString> arguments, ConstWeakArray<CString> environment)
  50. {
  51. ANKI_CHECK(refresh(0));
  52. if(m_status == ProcessStatus::RUNNING)
  53. {
  54. ANKI_UTIL_LOGE("Process already running");
  55. return Error::USER_DATA;
  56. }
  57. // Create the pipes
  58. ANKI_CHECK(createPipes());
  59. // Fork
  60. m_pid = fork();
  61. if(m_pid < 0)
  62. {
  63. ANKI_UTIL_LOGE("fork() failed: %s", strerror(errno));
  64. }
  65. if(m_pid == 0)
  66. {
  67. // Child
  68. dup2(m_stdoutPipe[1], 1);
  69. close(m_stdoutPipe[0]);
  70. m_stdoutPipe[0] = -1;
  71. dup2(m_stderrPipe[1], 2);
  72. close(m_stderrPipe[0]);
  73. m_stderrPipe[0] = -1;
  74. // Set the args
  75. char** cargs = static_cast<char**>(malloc((arguments.getSize() + 2) * sizeof(char*)));
  76. cargs[0] = static_cast<char*>(malloc(executable.getLength() + 1));
  77. strcpy(cargs[0], executable.cstr());
  78. U32 i = 0;
  79. for(; i < arguments.getSize(); ++i)
  80. {
  81. cargs[i + 1] = static_cast<char*>(malloc(arguments[i].getLength() + 1));
  82. strcpy(cargs[i + 1], arguments[i].cstr());
  83. }
  84. cargs[i + 1] = nullptr;
  85. // Set the env
  86. for(U32 i = 0; i < environment.getSize(); i += 2)
  87. {
  88. setenv(environment[i].cstr(), environment[i + 1].cstr(), 1);
  89. }
  90. // Execute file
  91. const int execerror = execvp(executable.cstr(), cargs);
  92. if(execerror)
  93. {
  94. printf("execvp() failed: %s", strerror(errno));
  95. exit(1);
  96. }
  97. }
  98. else
  99. {
  100. close(m_stdoutPipe[1]);
  101. m_stdoutPipe[1] = -1;
  102. close(m_stderrPipe[1]);
  103. m_stderrPipe[1] = -1;
  104. }
  105. return Error::NONE;
  106. }
  107. Error Process::kill(ProcessKillSignal k)
  108. {
  109. if(m_pid < 1)
  110. {
  111. return Error::NONE;
  112. }
  113. int sig;
  114. switch(k)
  115. {
  116. case ProcessKillSignal::NORMAL:
  117. sig = SIGTERM;
  118. break;
  119. case ProcessKillSignal::FORCE:
  120. sig = SIGKILL;
  121. break;
  122. default:
  123. ANKI_ASSERT(0);
  124. sig = 0;
  125. };
  126. const pid_t p = ::kill(m_pid, sig);
  127. if(p != 0)
  128. {
  129. ANKI_UTIL_LOGE("kill() failed: %s", strerror(errno));
  130. return Error::FUNCTION_FAILED;
  131. }
  132. return Error::NONE;
  133. }
  134. Error Process::readFromFd(int fd, StringAuto& text) const
  135. {
  136. fd_set readfds;
  137. FD_ZERO(&readfds);
  138. FD_SET(fd, &readfds);
  139. timeval timeout;
  140. timeout.tv_sec = 0; // Seconds
  141. timeout.tv_usec = 10; // Microseconds
  142. // Limit the iterations in case the process writes to FD constantly
  143. U32 maxIterations = 16;
  144. while(maxIterations--)
  145. {
  146. // Check if there are data
  147. const int sel = select(1 + fd, &readfds, nullptr, nullptr, &timeout);
  148. if(sel == 0)
  149. {
  150. // Timeout expired
  151. break;
  152. }
  153. else if(sel == -1)
  154. {
  155. ANKI_UTIL_LOGE("select() failed: %s", strerror(errno));
  156. return Error::FUNCTION_FAILED;
  157. }
  158. // Read the data
  159. Array<char, 1024> buff;
  160. const ssize_t bytesCount = read(fd, buff.getBegin(), buff.getSize() - 1);
  161. if(bytesCount < 0 && errno != EAGAIN)
  162. {
  163. // NOTE errno == EINTR if a non-fatal signal arrived
  164. ANKI_UTIL_LOGE("read() failed: %s", strerror(errno));
  165. return Error::FUNCTION_FAILED;
  166. }
  167. else if(bytesCount == 0)
  168. {
  169. break;
  170. }
  171. else
  172. {
  173. buff[min<U32>(U32(bytesCount), buff.getSize() - 1)] = '\0';
  174. text.append(&buff[0]);
  175. }
  176. }
  177. return Error::NONE;
  178. }
  179. Error Process::readFromStdout(StringAuto& text)
  180. {
  181. return readFromFd(m_stdoutPipe[0], text);
  182. }
  183. Error Process::readFromStderr(StringAuto& text)
  184. {
  185. return readFromFd(m_stderrPipe[0], text);
  186. }
  187. Error Process::getStatus(ProcessStatus& status)
  188. {
  189. ANKI_CHECK(refresh(WNOHANG));
  190. status = m_status;
  191. return Error::NONE;
  192. }
  193. Error Process::refresh(int waitpidOptions)
  194. {
  195. Error err = Error::NONE;
  196. m_status = ProcessStatus::NOT_RUNNING;
  197. m_exitCode = DEFAULT_EXIT_CODE;
  198. if(m_pid == -1)
  199. {
  200. m_status = ProcessStatus::NOT_RUNNING;
  201. m_exitCode = DEFAULT_EXIT_CODE;
  202. }
  203. else
  204. {
  205. int status;
  206. const pid_t p = waitpid(m_pid, &status, waitpidOptions);
  207. if(p == -1)
  208. {
  209. m_status = ProcessStatus::NOT_RUNNING;
  210. m_exitCode = DEFAULT_EXIT_CODE;
  211. m_pid = -1;
  212. ANKI_UTIL_LOGE("waitpid() failed: %s", strerror(errno));
  213. err = Error::FUNCTION_FAILED;
  214. }
  215. else if(p == 0)
  216. {
  217. m_status = ProcessStatus::RUNNING;
  218. m_exitCode = DEFAULT_EXIT_CODE;
  219. }
  220. else if(WIFEXITED(status))
  221. {
  222. m_status = ProcessStatus::NORMAL_EXIT;
  223. m_exitCode = WEXITSTATUS(status);
  224. m_pid = -1;
  225. }
  226. else if(WIFSIGNALED(status))
  227. {
  228. m_status = ProcessStatus::CRASH_EXIT;
  229. m_exitCode = WTERMSIG(status);
  230. m_pid = -1;
  231. }
  232. else if(WIFSTOPPED(status))
  233. {
  234. // NOTE child may resume later (and become a zombie)
  235. m_status = ProcessStatus::CRASH_EXIT;
  236. m_exitCode = WSTOPSIG(status);
  237. }
  238. else
  239. {
  240. ANKI_ASSERT(0);
  241. }
  242. }
  243. return err;
  244. }
  245. Error Process::wait(Second timeout, ProcessStatus* status, I32* exitCode)
  246. {
  247. ANKI_CHECK(refresh(0));
  248. if(status)
  249. {
  250. *status = m_status;
  251. }
  252. if(exitCode)
  253. {
  254. *exitCode = m_exitCode;
  255. }
  256. return Error::NONE;
  257. }
  258. } // end namespace anki