antithread.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. #include <stdlib.h>
  2. #include <unistd.h>
  3. #include <fcntl.h>
  4. #include <stdbool.h>
  5. #include <string.h>
  6. #include <sys/mman.h>
  7. #include <sys/types.h>
  8. #include <sys/wait.h>
  9. #include <errno.h>
  10. #include <assert.h>
  11. #include <err.h>
  12. #include "antithread.h"
  13. #include <ccan/noerr/noerr.h>
  14. #include <ccan/talloc/talloc.h>
  15. #include <ccan/read_write_all/read_write_all.h>
  16. #include <ccan/alloc/alloc.h>
  17. #include <ccan/list/list.h>
  18. /* FIXME: Valgrind support should be possible for some cases. Tricky
  19. * case is where another process allocates for you, but at worst we
  20. * could reset what is valid and what isn't on every entry into the
  21. * library or something. */
  22. static LIST_HEAD(pools);
  23. /* Talloc destroys parents before children (damn Tridge's failing destructors!)
  24. * so we need the first child (ie. last-destroyed) to actually clean up. */
  25. struct at_pool_contents {
  26. struct list_node list;
  27. void *pool;
  28. unsigned long poolsize;
  29. int fd;
  30. int parent_rfd, parent_wfd;
  31. struct at_pool *atp;
  32. };
  33. struct at_pool {
  34. struct at_pool_contents *p;
  35. const void *ctx;
  36. };
  37. struct athread {
  38. pid_t pid;
  39. int rfd, wfd;
  40. };
  41. /* FIXME: Better locking through futexes. */
  42. static void lock(int fd, unsigned long off)
  43. {
  44. struct flock fl;
  45. fl.l_type = F_WRLCK;
  46. fl.l_whence = SEEK_SET;
  47. fl.l_start = off;
  48. fl.l_len = 1;
  49. while (fcntl(fd, F_SETLKW, &fl) < 0) {
  50. if (errno != EINTR)
  51. err(1, "Failure locking antithread file");
  52. }
  53. }
  54. static void unlock(int fd, unsigned long off)
  55. {
  56. struct flock fl;
  57. int serrno = errno;
  58. fl.l_type = F_UNLCK;
  59. fl.l_whence = SEEK_SET;
  60. fl.l_start = off;
  61. fl.l_len = 1;
  62. fcntl(fd, F_SETLK, &fl);
  63. errno = serrno;
  64. }
  65. /* This pointer is in a pool. Find which one. */
  66. static struct at_pool_contents *find_pool(const void *ptr)
  67. {
  68. struct at_pool_contents *p;
  69. list_for_each(&pools, p, list) {
  70. /* Special case for initial allocation: ptr *is* pool */
  71. if (ptr == p->atp)
  72. return p;
  73. if ((char *)ptr >= (char *)p->pool
  74. && (char *)ptr < (char *)p->pool + p->poolsize)
  75. return p;
  76. }
  77. abort();
  78. }
  79. static int destroy_pool(struct at_pool_contents *p)
  80. {
  81. list_del(&p->list);
  82. munmap(p->pool, p->poolsize);
  83. close(p->fd);
  84. close(p->parent_rfd);
  85. close(p->parent_wfd);
  86. return 0;
  87. }
  88. static void *at_realloc(const void *parent, void *ptr, size_t size)
  89. {
  90. struct at_pool_contents *p = find_pool(parent);
  91. /* FIXME: realloc in ccan/alloc? */
  92. void *new;
  93. if (size == 0) {
  94. alloc_free(p->pool, p->poolsize, ptr);
  95. new = NULL;
  96. } else if (ptr == NULL) {
  97. /* FIXME: Alignment */
  98. new = alloc_get(p->pool, p->poolsize, size, 16);
  99. } else {
  100. if (size <= alloc_size(p->pool, p->poolsize, ptr))
  101. new = ptr;
  102. else {
  103. new = alloc_get(p->pool, p->poolsize, size, 16);
  104. if (new) {
  105. memcpy(new, ptr,
  106. alloc_size(p->pool, p->poolsize, ptr));
  107. alloc_free(p->pool, p->poolsize, ptr);
  108. }
  109. }
  110. }
  111. return new;
  112. }
  113. static struct at_pool_contents *locked;
  114. static void talloc_lock(const void *ptr)
  115. {
  116. struct at_pool_contents *p = find_pool(ptr);
  117. lock(p->fd, 0);
  118. assert(!locked);
  119. locked = p;
  120. }
  121. static void talloc_unlock(void)
  122. {
  123. struct at_pool_contents *p = locked;
  124. locked = NULL;
  125. unlock(p->fd, 0);
  126. }
  127. /* We add 16MB to size. This compensates for address randomization. */
  128. #define PADDING (16 * 1024 * 1024)
  129. /* Create a new sharable pool. */
  130. struct at_pool *at_pool(unsigned long size)
  131. {
  132. int fd;
  133. struct at_pool *atp;
  134. struct at_pool_contents *p;
  135. FILE *f;
  136. /* FIXME: How much should we actually add for overhead?. */
  137. size += 32 * getpagesize();
  138. /* Round up to whole pages. */
  139. size = (size + getpagesize()-1) & ~(getpagesize()-1);
  140. f = tmpfile();
  141. if (!f)
  142. return NULL;
  143. fd = dup(fileno(f));
  144. fclose_noerr(f);
  145. if (fd < 0)
  146. return NULL;
  147. if (ftruncate(fd, size + PADDING) != 0)
  148. goto fail_close;
  149. atp = talloc(NULL, struct at_pool);
  150. if (!atp)
  151. goto fail_close;
  152. atp->p = p = talloc(NULL, struct at_pool_contents);
  153. if (!p)
  154. goto fail_free;
  155. /* First map gets a nice big area. */
  156. p->pool = mmap(NULL, size+PADDING, PROT_READ|PROT_WRITE, MAP_SHARED, fd,
  157. 0);
  158. if (p->pool == MAP_FAILED)
  159. goto fail_free;
  160. /* Then we remap into the middle of it. */
  161. munmap(p->pool, size+PADDING);
  162. p->pool = mmap(p->pool + PADDING/2, size, PROT_READ|PROT_WRITE,
  163. MAP_SHARED, fd, 0);
  164. if (p->pool == MAP_FAILED)
  165. goto fail_free;
  166. p->fd = fd;
  167. p->poolsize = size;
  168. p->parent_rfd = p->parent_wfd = -1;
  169. p->atp = atp;
  170. alloc_init(p->pool, p->poolsize);
  171. list_add(&pools, &p->list);
  172. talloc_set_destructor(p, destroy_pool);
  173. atp->ctx = talloc_add_external(atp,
  174. at_realloc, talloc_lock, talloc_unlock);
  175. if (!atp->ctx)
  176. goto fail_free;
  177. return atp;
  178. fail_free:
  179. talloc_free(atp);
  180. fail_close:
  181. close_noerr(fd);
  182. return NULL;
  183. }
  184. /* Talloc off this to allocate from within the pool. */
  185. const void *at_pool_ctx(struct at_pool *atp)
  186. {
  187. return atp->ctx;
  188. }
  189. static int cant_destroy_self(struct athread *at)
  190. {
  191. /* Perhaps this means we want to detach, but it doesn't really
  192. * make sense. */
  193. abort();
  194. return 0;
  195. }
  196. static int destroy_at(struct athread *at)
  197. {
  198. /* If it is already a zombie, this is harmless. */
  199. kill(at->pid, SIGTERM);
  200. close(at->rfd);
  201. close(at->wfd);
  202. /* FIXME: Should we do SIGKILL if process doesn't exit soon? */
  203. if (waitpid(at->pid, NULL, 0) != at->pid)
  204. err(1, "Waiting for athread %p (pid %u)", at, at->pid);
  205. return 0;
  206. }
  207. /* Sets up thread and forks it. NULL on error. */
  208. static struct athread *fork_thread(struct at_pool *atp)
  209. {
  210. int p2c[2], c2p[2];
  211. struct athread *at;
  212. struct at_pool_contents *pool = atp->p;
  213. /* You can't already be a child of this pool. */
  214. if (pool->parent_rfd != -1)
  215. errx(1, "Can't create antithread on this pool: we're one");
  216. /* We don't want this allocated *in* the pool. */
  217. at = talloc_steal(atp, talloc(NULL, struct athread));
  218. if (pipe(p2c) != 0)
  219. goto free;
  220. if (pipe(c2p) != 0)
  221. goto close_p2c;
  222. at->pid = fork();
  223. if (at->pid == -1)
  224. goto close_c2p;
  225. if (at->pid == 0) {
  226. /* Child */
  227. close(c2p[0]);
  228. close(p2c[1]);
  229. pool->parent_rfd = p2c[0];
  230. pool->parent_wfd = c2p[1];
  231. talloc_set_destructor(at, cant_destroy_self);
  232. } else {
  233. /* Parent */
  234. close(c2p[1]);
  235. close(p2c[0]);
  236. at->rfd = c2p[0];
  237. at->wfd = p2c[1];
  238. talloc_set_destructor(at, destroy_at);
  239. }
  240. return at;
  241. close_c2p:
  242. close_noerr(c2p[0]);
  243. close_noerr(c2p[1]);
  244. close_p2c:
  245. close_noerr(p2c[0]);
  246. close_noerr(p2c[1]);
  247. free:
  248. talloc_free(at);
  249. return NULL;
  250. }
  251. /* Creating an antithread via fork() */
  252. struct athread *_at_run(struct at_pool *atp,
  253. void *(*fn)(struct at_pool *, void *),
  254. void *obj)
  255. {
  256. struct athread *at;
  257. at = fork_thread(atp);
  258. if (!at)
  259. return NULL;
  260. if (at->pid == 0) {
  261. /* Child */
  262. at_tell_parent(atp, fn(atp, obj));
  263. exit(0);
  264. }
  265. /* Parent */
  266. return at;
  267. }
  268. static unsigned int num_args(char *const argv[])
  269. {
  270. unsigned int i;
  271. for (i = 0; argv[i]; i++);
  272. return i;
  273. }
  274. /* Fork and execvp, with added arguments for child to grab. */
  275. struct athread *at_spawn(struct at_pool *atp, void *arg, char *cmdline[])
  276. {
  277. struct athread *at;
  278. int err;
  279. at = fork_thread(atp);
  280. if (!at)
  281. return NULL;
  282. if (at->pid == 0) {
  283. /* child */
  284. char *argv[num_args(cmdline) + 2];
  285. argv[0] = cmdline[0];
  286. argv[1] = talloc_asprintf(NULL, "AT:%p/%lu/%i/%i/%i/%p",
  287. atp->p->pool, atp->p->poolsize,
  288. atp->p->fd, atp->p->parent_rfd,
  289. atp->p->parent_wfd, arg);
  290. /* Copy including NULL terminator. */
  291. memcpy(&argv[2], &cmdline[1], num_args(cmdline)*sizeof(char *));
  292. execvp(argv[0], argv);
  293. err = errno;
  294. write_all(atp->p->parent_wfd, &err, sizeof(err));
  295. exit(1);
  296. }
  297. /* Child should always write an error code (or 0). */
  298. if (read(at->rfd, &err, sizeof(err)) != sizeof(err)) {
  299. errno = ECHILD;
  300. talloc_free(at);
  301. return NULL;
  302. }
  303. if (err != 0) {
  304. errno = err;
  305. talloc_free(at);
  306. return NULL;
  307. }
  308. return at;
  309. }
  310. /* The fd to poll on */
  311. int at_fd(struct athread *at)
  312. {
  313. return at->rfd;
  314. }
  315. /* What's the antithread saying? Blocks if fd not ready. */
  316. void *at_read(struct athread *at)
  317. {
  318. void *ret;
  319. switch (read(at->rfd, &ret, sizeof(ret))) {
  320. case -1:
  321. err(1, "Reading from athread %p (pid %u)", at, at->pid);
  322. case 0:
  323. /* Thread died. */
  324. return NULL;
  325. case sizeof(ret):
  326. return ret;
  327. default:
  328. /* Should never happen. */
  329. err(1, "Short read from athread %p (pid %u)", at, at->pid);
  330. }
  331. }
  332. /* Say something to a child. */
  333. void at_tell(struct athread *at, const void *status)
  334. {
  335. if (write(at->wfd, &status, sizeof(status)) != sizeof(status))
  336. err(1, "Failure writing to athread %p (pid %u)", at, at->pid);
  337. }
  338. /* For child to grab arguments from command line (removes them) */
  339. struct at_pool *at_get_pool(int *argc, char *argv[], void **arg)
  340. {
  341. struct at_pool *atp = talloc(NULL, struct at_pool);
  342. struct at_pool_contents *p;
  343. void *map;
  344. int err;
  345. if (!argv[1]) {
  346. errno = EINVAL;
  347. goto fail;
  348. }
  349. /* If they don't care, use dummy value. */
  350. if (arg == NULL)
  351. arg = &map;
  352. p = atp->p = talloc(atp, struct at_pool_contents);
  353. if (sscanf(argv[1], "AT:%p/%lu/%i/%i/%i/%p",
  354. &p->pool, &p->poolsize, &p->fd,
  355. &p->parent_rfd, &p->parent_wfd, arg) != 6) {
  356. errno = EINVAL;
  357. goto fail;
  358. }
  359. /* FIXME: To try to adjust for address space randomization, we
  360. * could re-exec a few times. */
  361. map = mmap(p->pool, p->poolsize, PROT_READ|PROT_WRITE, MAP_SHARED,
  362. p->fd, 0);
  363. if (map != p->pool) {
  364. fprintf(stderr, "Mapping %lu bytes @%p gave %p\n",
  365. p->poolsize, p->pool, map);
  366. errno = ENOMEM;
  367. goto fail;
  368. }
  369. list_add(&pools, &p->list);
  370. talloc_set_destructor(p, destroy_pool);
  371. p->atp = atp;
  372. atp->ctx = talloc_add_external(atp,
  373. at_realloc, talloc_lock, talloc_unlock);
  374. if (!atp->ctx)
  375. goto fail;
  376. /* Tell parent we're good. */
  377. err = 0;
  378. if (write(p->parent_wfd, &err, sizeof(err)) != sizeof(err)) {
  379. errno = EBADF;
  380. goto fail;
  381. }
  382. /* Delete AT arg. */
  383. memmove(&argv[1], &argv[2], --(*argc));
  384. return atp;
  385. fail:
  386. talloc_free(atp);
  387. return NULL;
  388. }
  389. /* Say something to our parent (async). */
  390. void at_tell_parent(struct at_pool *atp, const void *status)
  391. {
  392. if (atp->p->parent_wfd == -1)
  393. errx(1, "This process is not an antithread of this pool");
  394. if (write(atp->p->parent_wfd, &status, sizeof(status))!=sizeof(status))
  395. err(1, "Failure writing to parent");
  396. }
  397. /* What's the parent saying? Blocks if fd not ready. */
  398. void *at_read_parent(struct at_pool *atp)
  399. {
  400. void *ret;
  401. if (atp->p->parent_rfd == -1)
  402. errx(1, "This process is not an antithread of this pool");
  403. switch (read(atp->p->parent_rfd, &ret, sizeof(ret))) {
  404. case -1:
  405. err(1, "Reading from parent");
  406. case 0:
  407. /* Parent died. */
  408. return NULL;
  409. case sizeof(ret):
  410. return ret;
  411. default:
  412. /* Should never happen. */
  413. err(1, "Short read from parent");
  414. }
  415. }
  416. /* The fd to poll on */
  417. int at_parent_fd(struct at_pool *atp)
  418. {
  419. if (atp->p->parent_rfd == -1)
  420. errx(1, "This process is not an antithread of this pool");
  421. return atp->p->parent_rfd;
  422. }
  423. /* FIXME: Futexme. */
  424. void at_lock(void *obj)
  425. {
  426. struct at_pool *atp = talloc_find_parent_bytype(obj, struct at_pool);
  427. #if 0
  428. unsigned int *l;
  429. /* This isn't required yet, but ensures it's a talloc ptr */
  430. l = talloc_lock_ptr(obj);
  431. #endif
  432. lock(atp->p->fd, (char *)obj - (char *)atp->p->pool);
  433. #if 0
  434. if (*l)
  435. errx(1, "Object %p was already locked (something died?)", obj);
  436. *l = 1;
  437. #endif
  438. }
  439. void at_unlock(void *obj)
  440. {
  441. struct at_pool *atp = talloc_find_parent_bytype(obj, struct at_pool);
  442. #if 0
  443. unsigned int *l;
  444. l = talloc_lock_ptr(obj);
  445. if (!*l)
  446. errx(1, "Object %p was already unlocked", obj);
  447. *l = 0;
  448. #endif
  449. unlock(atp->p->fd, (char *)obj - (char *)atp->p->pool);
  450. }
  451. void at_lock_all(struct at_pool *atp)
  452. {
  453. lock(atp->p->fd, 0);
  454. }
  455. void at_unlock_all(struct at_pool *atp)
  456. {
  457. unlock(atp->p->fd, 0);
  458. }