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

674 lines
17 KiB

10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2012-2013, RedJack, LLC.
  4. * All rights reserved.
  5. *
  6. * Please see the COPYING file in this distribution for license
  7. * details.
  8. * ----------------------------------------------------------------------
  9. */
  10. #include <assert.h>
  11. #include <errno.h>
  12. #include <fcntl.h>
  13. #include <signal.h>
  14. #include <sys/select.h>
  15. #include <sys/wait.h>
  16. #include <unistd.h>
  17. #include "libcork/core.h"
  18. #include "libcork/ds.h"
  19. #include "libcork/os/subprocess.h"
  20. #include "libcork/threads/basics.h"
  21. #include "libcork/helpers/errors.h"
  22. #include "libcork/helpers/posix.h"
  23. #if !defined(CORK_DEBUG_SUBPROCESS)
  24. #define CORK_DEBUG_SUBPROCESS 0
  25. #endif
  26. #if CORK_DEBUG_SUBPROCESS
  27. #include <stdio.h>
  28. #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
  29. #else
  30. #define DEBUG(...) /* no debug messages */
  31. #endif
  32. /*-----------------------------------------------------------------------
  33. * Subprocess groups
  34. */
  35. #define BUF_SIZE 4096
  36. struct cork_subprocess_group {
  37. cork_array(struct cork_subprocess *) subprocesses;
  38. };
  39. struct cork_subprocess_group *
  40. cork_subprocess_group_new(void)
  41. {
  42. struct cork_subprocess_group *group =
  43. cork_new(struct cork_subprocess_group);
  44. cork_pointer_array_init
  45. (&group->subprocesses, (cork_free_f) cork_subprocess_free);
  46. return group;
  47. }
  48. void
  49. cork_subprocess_group_free(struct cork_subprocess_group *group)
  50. {
  51. cork_array_done(&group->subprocesses);
  52. free(group);
  53. }
  54. void
  55. cork_subprocess_group_add(struct cork_subprocess_group *group,
  56. struct cork_subprocess *sub)
  57. {
  58. cork_array_append(&group->subprocesses, sub);
  59. }
  60. /*-----------------------------------------------------------------------
  61. * Pipes (parent reads)
  62. */
  63. struct cork_read_pipe {
  64. struct cork_stream_consumer *consumer;
  65. int fds[2];
  66. bool first;
  67. };
  68. static void
  69. cork_read_pipe_init(struct cork_read_pipe *p, struct cork_stream_consumer *consumer)
  70. {
  71. p->consumer = consumer;
  72. p->fds[0] = -1;
  73. p->fds[1] = -1;
  74. }
  75. static int
  76. cork_read_pipe_close_read(struct cork_read_pipe *p)
  77. {
  78. if (p->fds[0] != -1) {
  79. DEBUG("Closing read pipe %d\n", p->fds[0]);
  80. rii_check_posix(close(p->fds[0]));
  81. p->fds[0] = -1;
  82. }
  83. return 0;
  84. }
  85. static int
  86. cork_read_pipe_close_write(struct cork_read_pipe *p)
  87. {
  88. if (p->fds[1] != -1) {
  89. DEBUG("Closing write pipe %d\n", p->fds[1]);
  90. rii_check_posix(close(p->fds[1]));
  91. p->fds[1] = -1;
  92. }
  93. return 0;
  94. }
  95. static void
  96. cork_read_pipe_close(struct cork_read_pipe *p)
  97. {
  98. cork_read_pipe_close_read(p);
  99. cork_read_pipe_close_write(p);
  100. }
  101. static void
  102. cork_read_pipe_done(struct cork_read_pipe *p)
  103. {
  104. cork_read_pipe_close(p);
  105. }
  106. static int
  107. cork_read_pipe_open(struct cork_read_pipe *p)
  108. {
  109. if (p->consumer != NULL) {
  110. int flags;
  111. /* We want the read end of the pipe to be non-blocking. */
  112. DEBUG("[read] Opening pipe\n");
  113. rii_check_posix(pipe(p->fds));
  114. DEBUG("[read] Got read=%d write=%d\n", p->fds[0], p->fds[1]);
  115. DEBUG("[read] Setting non-blocking flag on read pipe\n");
  116. ei_check_posix(flags = fcntl(p->fds[0], F_GETFD));
  117. flags |= O_NONBLOCK;
  118. ei_check_posix(fcntl(p->fds[0], F_SETFD, flags));
  119. }
  120. p->first = true;
  121. return 0;
  122. error:
  123. cork_read_pipe_close(p);
  124. return -1;
  125. }
  126. static int
  127. cork_read_pipe_dup(struct cork_read_pipe *p, int fd)
  128. {
  129. if (p->fds[1] != -1) {
  130. rii_check_posix(dup2(p->fds[1], fd));
  131. }
  132. return 0;
  133. }
  134. static int
  135. cork_read_pipe_read(struct cork_read_pipe *p, char *buf, bool *progress)
  136. {
  137. if (p->fds[0] == -1) {
  138. return 0;
  139. }
  140. do {
  141. DEBUG("[read] Reading from pipe %d\n", p->fds[0]);
  142. ssize_t bytes_read = read(p->fds[0], buf, BUF_SIZE);
  143. if (bytes_read == -1) {
  144. if (errno == EAGAIN) {
  145. /* We've exhausted all of the data currently available. */
  146. DEBUG("[read] No more bytes without blocking\n");
  147. return 0;
  148. } else if (errno == EINTR) {
  149. /* Interrupted by a signal; return so that our wait loop can
  150. * catch that. */
  151. DEBUG("[read] Interrupted by signal\n");
  152. return 0;
  153. } else {
  154. /* An actual error */
  155. cork_system_error_set();
  156. DEBUG("[read] Error: %s\n", cork_error_message());
  157. return -1;
  158. }
  159. } else if (bytes_read == 0) {
  160. DEBUG("[read] End of stream\n");
  161. *progress = true;
  162. rii_check(cork_stream_consumer_eof(p->consumer));
  163. rii_check_posix(close(p->fds[0]));
  164. p->fds[0] = -1;
  165. return 0;
  166. } else {
  167. DEBUG("[read] Got %zd bytes\n", bytes_read);
  168. *progress = true;
  169. rii_check(cork_stream_consumer_data
  170. (p->consumer, buf, bytes_read, p->first));
  171. p->first = false;
  172. }
  173. } while (true);
  174. }
  175. static bool
  176. cork_read_pipe_is_finished(struct cork_read_pipe *p)
  177. {
  178. return p->fds[0] == -1;
  179. }
  180. /*-----------------------------------------------------------------------
  181. * Pipes (parent writes)
  182. */
  183. struct cork_write_pipe {
  184. struct cork_stream_consumer consumer;
  185. int fds[2];
  186. };
  187. static int
  188. cork_write_pipe_close_read(struct cork_write_pipe *p)
  189. {
  190. if (p->fds[0] != -1) {
  191. DEBUG("[write] Closing read pipe %d\n", p->fds[0]);
  192. rii_check_posix(close(p->fds[0]));
  193. p->fds[0] = -1;
  194. }
  195. return 0;
  196. }
  197. static int
  198. cork_write_pipe_close_write(struct cork_write_pipe *p)
  199. {
  200. if (p->fds[1] != -1) {
  201. DEBUG("[write] Closing write pipe %d\n", p->fds[1]);
  202. rii_check_posix(close(p->fds[1]));
  203. p->fds[1] = -1;
  204. }
  205. return 0;
  206. }
  207. static int
  208. cork_write_pipe__data(struct cork_stream_consumer *consumer,
  209. const void *buf, size_t size, bool is_first_chunk)
  210. {
  211. struct cork_write_pipe *p =
  212. cork_container_of(consumer, struct cork_write_pipe, consumer);
  213. rii_check_posix(write(p->fds[1], buf, size));
  214. return 0;
  215. }
  216. static int
  217. cork_write_pipe__eof(struct cork_stream_consumer *consumer)
  218. {
  219. struct cork_write_pipe *p =
  220. cork_container_of(consumer, struct cork_write_pipe, consumer);
  221. return cork_write_pipe_close_write(p);
  222. }
  223. static void
  224. cork_write_pipe__free(struct cork_stream_consumer *consumer)
  225. {
  226. }
  227. static void
  228. cork_write_pipe_init(struct cork_write_pipe *p)
  229. {
  230. p->consumer.data = cork_write_pipe__data;
  231. p->consumer.eof = cork_write_pipe__eof;
  232. p->consumer.free = cork_write_pipe__free;
  233. p->fds[0] = -1;
  234. p->fds[1] = -1;
  235. }
  236. static void
  237. cork_write_pipe_close(struct cork_write_pipe *p)
  238. {
  239. cork_write_pipe_close_read(p);
  240. cork_write_pipe_close_write(p);
  241. }
  242. static void
  243. cork_write_pipe_done(struct cork_write_pipe *p)
  244. {
  245. cork_write_pipe_close(p);
  246. }
  247. static int
  248. cork_write_pipe_open(struct cork_write_pipe *p)
  249. {
  250. DEBUG("[write] Opening writer pipe\n");
  251. rii_check_posix(pipe(p->fds));
  252. DEBUG("[write] Got read=%d write=%d\n", p->fds[0], p->fds[1]);
  253. return 0;
  254. }
  255. static int
  256. cork_write_pipe_dup(struct cork_write_pipe *p, int fd)
  257. {
  258. if (p->fds[0] != -1) {
  259. rii_check_posix(dup2(p->fds[0], fd));
  260. }
  261. return 0;
  262. }
  263. /*-----------------------------------------------------------------------
  264. * Subprocesses
  265. */
  266. struct cork_subprocess {
  267. pid_t pid;
  268. struct cork_write_pipe stdin_pipe;
  269. struct cork_read_pipe stdout_pipe;
  270. struct cork_read_pipe stderr_pipe;
  271. struct cork_thread_body *body;
  272. int *exit_code;
  273. char buf[BUF_SIZE];
  274. };
  275. struct cork_subprocess *
  276. cork_subprocess_new(struct cork_thread_body *body,
  277. struct cork_stream_consumer *stdout_consumer,
  278. struct cork_stream_consumer *stderr_consumer,
  279. int *exit_code)
  280. {
  281. struct cork_subprocess *self = cork_new(struct cork_subprocess);
  282. cork_write_pipe_init(&self->stdin_pipe);
  283. cork_read_pipe_init(&self->stdout_pipe, stdout_consumer);
  284. cork_read_pipe_init(&self->stderr_pipe, stderr_consumer);
  285. self->pid = 0;
  286. self->body = body;
  287. self->exit_code = exit_code;
  288. return self;
  289. }
  290. void
  291. cork_subprocess_free(struct cork_subprocess *self)
  292. {
  293. cork_thread_body_free(self->body);
  294. cork_write_pipe_done(&self->stdin_pipe);
  295. cork_read_pipe_done(&self->stdout_pipe);
  296. cork_read_pipe_done(&self->stderr_pipe);
  297. free(self);
  298. }
  299. struct cork_stream_consumer *
  300. cork_subprocess_stdin(struct cork_subprocess *self)
  301. {
  302. return &self->stdin_pipe.consumer;
  303. }
  304. /*-----------------------------------------------------------------------
  305. * Executing another program
  306. */
  307. struct cork_exec_body {
  308. struct cork_thread_body parent;
  309. struct cork_exec *exec;
  310. };
  311. static int
  312. cork_exec__run(struct cork_thread_body *vself)
  313. {
  314. struct cork_exec_body *self =
  315. cork_container_of(vself, struct cork_exec_body, parent);
  316. return cork_exec_run(self->exec);
  317. }
  318. static void
  319. cork_exec__free(struct cork_thread_body *vself)
  320. {
  321. struct cork_exec_body *self =
  322. cork_container_of(vself, struct cork_exec_body, parent);
  323. cork_exec_free(self->exec);
  324. free(self);
  325. }
  326. static struct cork_thread_body *
  327. cork_exec_body_new(struct cork_exec *exec)
  328. {
  329. struct cork_exec_body *self = cork_new(struct cork_exec_body);
  330. self->parent.run = cork_exec__run;
  331. self->parent.free = cork_exec__free;
  332. self->exec = exec;
  333. return &self->parent;
  334. }
  335. struct cork_subprocess *
  336. cork_subprocess_new_exec(struct cork_exec *exec,
  337. struct cork_stream_consumer *out,
  338. struct cork_stream_consumer *err,
  339. int *exit_code)
  340. {
  341. struct cork_thread_body *body = cork_exec_body_new(exec);
  342. return cork_subprocess_new(body, out, err, exit_code);
  343. }
  344. /*-----------------------------------------------------------------------
  345. * Running subprocesses
  346. */
  347. int
  348. cork_subprocess_start(struct cork_subprocess *self)
  349. {
  350. pid_t pid;
  351. /* Create the stdout and stderr pipes. */
  352. if (cork_write_pipe_open(&self->stdin_pipe) == -1) {
  353. return -1;
  354. }
  355. if (cork_read_pipe_open(&self->stdout_pipe) == -1) {
  356. cork_write_pipe_close(&self->stdin_pipe);
  357. return -1;
  358. }
  359. if (cork_read_pipe_open(&self->stderr_pipe) == -1) {
  360. cork_write_pipe_close(&self->stdin_pipe);
  361. cork_read_pipe_close(&self->stdout_pipe);
  362. return -1;
  363. }
  364. /* Fork the child process. */
  365. DEBUG("Forking child process\n");
  366. pid = fork();
  367. if (pid == 0) {
  368. /* Child process */
  369. int rc;
  370. /* Close the parent's end of the pipes */
  371. DEBUG("[child] ");
  372. cork_write_pipe_close_write(&self->stdin_pipe);
  373. DEBUG("[child] ");
  374. cork_read_pipe_close_read(&self->stdout_pipe);
  375. DEBUG("[child] ");
  376. cork_read_pipe_close_read(&self->stderr_pipe);
  377. /* Bind the stdout and stderr pipes */
  378. if (cork_write_pipe_dup(&self->stdin_pipe, STDIN_FILENO) == -1) {
  379. _exit(EXIT_FAILURE);
  380. }
  381. if (cork_read_pipe_dup(&self->stdout_pipe, STDOUT_FILENO) == -1) {
  382. _exit(EXIT_FAILURE);
  383. }
  384. if (cork_read_pipe_dup(&self->stderr_pipe, STDERR_FILENO) == -1) {
  385. _exit(EXIT_FAILURE);
  386. }
  387. /* Run the subprocess's body */
  388. rc = cork_thread_body_run(self->body);
  389. if (CORK_LIKELY(rc == 0)) {
  390. _exit(EXIT_SUCCESS);
  391. } else {
  392. fprintf(stderr, "%s\n", cork_error_message());
  393. _exit(EXIT_FAILURE);
  394. }
  395. } else if (pid < 0) {
  396. /* Error forking */
  397. cork_system_error_set();
  398. return -1;
  399. } else {
  400. /* Parent process */
  401. DEBUG(" Child PID=%d\n", (int) pid);
  402. self->pid = pid;
  403. cork_write_pipe_close_read(&self->stdin_pipe);
  404. cork_read_pipe_close_write(&self->stdout_pipe);
  405. cork_read_pipe_close_write(&self->stderr_pipe);
  406. return 0;
  407. }
  408. }
  409. static int
  410. cork_subprocess_reap(struct cork_subprocess *self, int flags, bool *progress)
  411. {
  412. int pid;
  413. int status;
  414. rii_check_posix(pid = waitpid(self->pid, &status, flags));
  415. if (pid == self->pid) {
  416. *progress = true;
  417. self->pid = 0;
  418. if (self->exit_code != NULL) {
  419. *self->exit_code = WEXITSTATUS(status);
  420. }
  421. }
  422. return 0;
  423. }
  424. int
  425. cork_subprocess_abort(struct cork_subprocess *self)
  426. {
  427. if (self->pid > 0) {
  428. CORK_ATTR_UNUSED bool progress;
  429. DEBUG("Terminating child process %d\n", (int) self->pid);
  430. kill(self->pid, SIGTERM);
  431. return cork_subprocess_reap(self, 0, &progress);
  432. } else {
  433. return 0;
  434. }
  435. }
  436. bool
  437. cork_subprocess_is_finished(struct cork_subprocess *self)
  438. {
  439. return (self->pid == 0)
  440. && cork_read_pipe_is_finished(&self->stdout_pipe)
  441. && cork_read_pipe_is_finished(&self->stderr_pipe);
  442. }
  443. #if defined(__APPLE__)
  444. #include <pthread.h>
  445. #define THREAD_YIELD pthread_yield_np
  446. #elif defined(__linux__) || defined(BSD)
  447. #include <sched.h>
  448. #define THREAD_YIELD sched_yield
  449. #else
  450. #error "Unknown thread yield implementation"
  451. #endif
  452. static void
  453. cork_subprocess_yield(unsigned int *spin_count)
  454. {
  455. /* Adapted from
  456. * http://www.1024cores.net/home/lock-free-algorithms/tricks/spinning */
  457. if (*spin_count < 10) {
  458. /* Spin-wait */
  459. cork_pause();
  460. } else if (*spin_count < 20) {
  461. /* A more intense spin-wait */
  462. int i;
  463. for (i = 0; i < 50; i++) {
  464. cork_pause();
  465. }
  466. } else if (*spin_count < 22) {
  467. THREAD_YIELD();
  468. } else if (*spin_count < 24) {
  469. usleep(0);
  470. } else if (*spin_count < 50) {
  471. usleep(1);
  472. } else if (*spin_count < 75) {
  473. usleep((*spin_count - 49) * 1000);
  474. } else {
  475. usleep(25000);
  476. }
  477. (*spin_count)++;
  478. }
  479. static int
  480. cork_subprocess_drain_(struct cork_subprocess *self, bool *progress)
  481. {
  482. rii_check(cork_read_pipe_read(&self->stdout_pipe, self->buf, progress));
  483. rii_check(cork_read_pipe_read(&self->stderr_pipe, self->buf, progress));
  484. if (self->pid > 0) {
  485. return cork_subprocess_reap(self, WNOHANG, progress);
  486. } else {
  487. return 0;
  488. }
  489. }
  490. bool
  491. cork_subprocess_drain(struct cork_subprocess *self)
  492. {
  493. bool progress;
  494. cork_subprocess_drain_(self, &progress);
  495. return progress;
  496. }
  497. int
  498. cork_subprocess_wait(struct cork_subprocess *self)
  499. {
  500. unsigned int spin_count = 0;
  501. bool progress;
  502. while (!cork_subprocess_is_finished(self)) {
  503. progress = false;
  504. rii_check(cork_subprocess_drain_(self, &progress));
  505. if (!progress) {
  506. cork_subprocess_yield(&spin_count);
  507. }
  508. }
  509. return 0;
  510. }
  511. /*-----------------------------------------------------------------------
  512. * Running subprocess groups
  513. */
  514. static int
  515. cork_subprocess_group_terminate(struct cork_subprocess_group *group)
  516. {
  517. size_t i;
  518. for (i = 0; i < cork_array_size(&group->subprocesses); i++) {
  519. struct cork_subprocess *sub = cork_array_at(&group->subprocesses, i);
  520. rii_check(cork_subprocess_abort(sub));
  521. }
  522. return 0;
  523. }
  524. int
  525. cork_subprocess_group_start(struct cork_subprocess_group *group)
  526. {
  527. size_t i;
  528. DEBUG("Starting subprocess group\n");
  529. /* Start each subprocess. */
  530. for (i = 0; i < cork_array_size(&group->subprocesses); i++) {
  531. struct cork_subprocess *sub = cork_array_at(&group->subprocesses, i);
  532. ei_check(cork_subprocess_start(sub));
  533. }
  534. return 0;
  535. error:
  536. cork_subprocess_group_terminate(group);
  537. return -1;
  538. }
  539. int
  540. cork_subprocess_group_abort(struct cork_subprocess_group *group)
  541. {
  542. DEBUG("Aborting subprocess group\n");
  543. return cork_subprocess_group_terminate(group);
  544. }
  545. bool
  546. cork_subprocess_group_is_finished(struct cork_subprocess_group *group)
  547. {
  548. size_t i;
  549. for (i = 0; i < cork_array_size(&group->subprocesses); i++) {
  550. struct cork_subprocess *sub = cork_array_at(&group->subprocesses, i);
  551. bool sub_finished = cork_subprocess_is_finished(sub);
  552. if (!sub_finished) {
  553. return false;
  554. }
  555. }
  556. return true;
  557. }
  558. static int
  559. cork_subprocess_group_drain_(struct cork_subprocess_group *group,
  560. bool *progress)
  561. {
  562. size_t i;
  563. for (i = 0; i < cork_array_size(&group->subprocesses); i++) {
  564. struct cork_subprocess *sub = cork_array_at(&group->subprocesses, i);
  565. rii_check(cork_subprocess_drain_(sub, progress));
  566. }
  567. return 0;
  568. }
  569. bool
  570. cork_subprocess_group_drain(struct cork_subprocess_group *group)
  571. {
  572. bool progress = false;
  573. cork_subprocess_group_drain_(group, &progress);
  574. return progress;
  575. }
  576. int
  577. cork_subprocess_group_wait(struct cork_subprocess_group *group)
  578. {
  579. unsigned int spin_count = 0;
  580. bool progress;
  581. DEBUG("Waiting for subprocess group to finish\n");
  582. while (!cork_subprocess_group_is_finished(group)) {
  583. progress = false;
  584. rii_check(cork_subprocess_group_drain_(group, &progress));
  585. if (!progress) {
  586. cork_subprocess_yield(&spin_count);
  587. }
  588. }
  589. return 0;
  590. }