Commit 387d1509 authored by Rusty Russell's avatar Rusty Russell

Adapt antithread to new talloc locking, and fix so talloc destructor

works.
parent d65da2db
...@@ -7,29 +7,39 @@ ...@@ -7,29 +7,39 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include <err.h> #include <err.h>
#include "antithread.h" #include "antithread.h"
#include <ccan/noerr/noerr.h> #include <ccan/noerr/noerr.h>
#include <ccan/talloc/talloc.h> #include <ccan/talloc/talloc.h>
#include <ccan/read_write_all/read_write_all.h> #include <ccan/read_write_all/read_write_all.h>
#include <ccan/alloc/alloc.h> #include <ccan/alloc/alloc.h>
#include <ccan/list/list.h>
/* FIXME: Valgrind support should be possible for some cases. Tricky /* FIXME: Valgrind support should be possible for some cases. Tricky
* case is where another process allocates for you, but at worst we * case is where another process allocates for you, but at worst we
* could reset what is valid and what isn't on every entry into the * could reset what is valid and what isn't on every entry into the
* library or something. */ * library or something. */
struct at_pool static LIST_HEAD(pools);
{
const void *ctx; /* Talloc destroys parents before children (damn Tridge's failing destructors!)
* so we need the first child (ie. last-destroyed) to actually clean up. */
struct at_pool_contents {
struct list_node list;
void *pool; void *pool;
unsigned long poolsize; unsigned long poolsize;
int fd; int fd;
int parent_rfd, parent_wfd; int parent_rfd, parent_wfd;
struct at_pool *atp;
}; };
struct athread struct at_pool {
{ struct at_pool_contents *p;
const void *ctx;
};
struct athread {
pid_t pid; pid_t pid;
int rfd, wfd; int rfd, wfd;
}; };
...@@ -64,13 +74,39 @@ static void unlock(int fd, unsigned long off) ...@@ -64,13 +74,39 @@ static void unlock(int fd, unsigned long off)
errno = serrno; errno = serrno;
} }
/* This pointer is in a pool. Find which one. */
static struct at_pool_contents *find_pool(const void *ptr)
{
struct at_pool_contents *p;
list_for_each(&pools, p, list) {
/* Special case for initial allocation: ptr *is* pool */
if (ptr == p->atp)
return p;
if ((char *)ptr >= (char *)p->pool
&& (char *)ptr < (char *)p->pool + p->poolsize)
return p;
}
abort();
}
static int destroy_pool(struct at_pool_contents *p)
{
list_del(&p->list);
munmap(p->pool, p->poolsize);
close(p->fd);
close(p->parent_rfd);
close(p->parent_wfd);
return 0;
}
static void *at_realloc(const void *parent, void *ptr, size_t size) static void *at_realloc(const void *parent, void *ptr, size_t size)
{ {
struct at_pool *p = talloc_find_parent_bytype(parent, struct at_pool); struct at_pool_contents *p = find_pool(parent);
/* FIXME: realloc in ccan/alloc? */ /* FIXME: realloc in ccan/alloc? */
void *new; void *new;
lock(p->fd, 0);
if (size == 0) { if (size == 0) {
alloc_free(p->pool, p->poolsize, ptr); alloc_free(p->pool, p->poolsize, ptr);
new = NULL; new = NULL;
...@@ -89,10 +125,28 @@ static void *at_realloc(const void *parent, void *ptr, size_t size) ...@@ -89,10 +125,28 @@ static void *at_realloc(const void *parent, void *ptr, size_t size)
} }
} }
} }
unlock(p->fd, 0);
return new; return new;
} }
static struct at_pool_contents *locked;
static void talloc_lock(const void *ptr)
{
struct at_pool_contents *p = find_pool(ptr);
lock(p->fd, 0);
assert(!locked);
locked = p;
}
static void talloc_unlock(void)
{
struct at_pool_contents *p = locked;
locked = NULL;
unlock(p->fd, 0);
}
/* We add 16MB to size. This compensates for address randomization. */ /* We add 16MB to size. This compensates for address randomization. */
#define PADDING (16 * 1024 * 1024) #define PADDING (16 * 1024 * 1024)
...@@ -100,7 +154,8 @@ static void *at_realloc(const void *parent, void *ptr, size_t size) ...@@ -100,7 +154,8 @@ static void *at_realloc(const void *parent, void *ptr, size_t size)
struct at_pool *at_pool(unsigned long size) struct at_pool *at_pool(unsigned long size)
{ {
int fd; int fd;
struct at_pool *p; struct at_pool *atp;
struct at_pool_contents *p;
FILE *f; FILE *f;
/* FIXME: How much should we actually add for overhead?. */ /* FIXME: How much should we actually add for overhead?. */
...@@ -122,10 +177,14 @@ struct at_pool *at_pool(unsigned long size) ...@@ -122,10 +177,14 @@ struct at_pool *at_pool(unsigned long size)
if (ftruncate(fd, size + PADDING) != 0) if (ftruncate(fd, size + PADDING) != 0)
goto fail_close; goto fail_close;
p = talloc(NULL, struct at_pool); atp = talloc(NULL, struct at_pool);
if (!p) if (!atp)
goto fail_close; goto fail_close;
atp->p = p = talloc(NULL, struct at_pool_contents);
if (!p)
goto fail_free;
/* First map gets a nice big area. */ /* First map gets a nice big area. */
p->pool = mmap(NULL, size+PADDING, PROT_READ|PROT_WRITE, MAP_SHARED, fd, p->pool = mmap(NULL, size+PADDING, PROT_READ|PROT_WRITE, MAP_SHARED, fd,
0); 0);
...@@ -139,22 +198,22 @@ struct at_pool *at_pool(unsigned long size) ...@@ -139,22 +198,22 @@ struct at_pool *at_pool(unsigned long size)
if (p->pool == MAP_FAILED) if (p->pool == MAP_FAILED)
goto fail_free; goto fail_free;
/* FIXME: Destructor? */
p->fd = fd; p->fd = fd;
p->poolsize = size; p->poolsize = size;
p->parent_rfd = p->parent_wfd = -1; p->parent_rfd = p->parent_wfd = -1;
p->atp = atp;
alloc_init(p->pool, p->poolsize); alloc_init(p->pool, p->poolsize);
list_add(&pools, &p->list);
talloc_set_destructor(p, destroy_pool);
p->ctx = talloc_add_external(p, at_realloc); atp->ctx = talloc_add_external(atp,
if (!p->ctx) at_realloc, talloc_lock, talloc_unlock);
goto fail_unmap; if (!atp->ctx)
goto fail_free;
return p; return atp;
fail_unmap:
munmap(p->pool, size);
fail_free: fail_free:
talloc_free(p); talloc_free(atp);
fail_close: fail_close:
close_noerr(fd); close_noerr(fd);
return NULL; return NULL;
...@@ -190,17 +249,18 @@ static int destroy_at(struct athread *at) ...@@ -190,17 +249,18 @@ static int destroy_at(struct athread *at)
} }
/* Sets up thread and forks it. NULL on error. */ /* Sets up thread and forks it. NULL on error. */
static struct athread *fork_thread(struct at_pool *pool) static struct athread *fork_thread(struct at_pool *atp)
{ {
int p2c[2], c2p[2]; int p2c[2], c2p[2];
struct athread *at; struct athread *at;
struct at_pool_contents *pool = atp->p;
/* You can't already be a child of this pool. */ /* You can't already be a child of this pool. */
if (pool->parent_rfd != -1) if (pool->parent_rfd != -1)
errx(1, "Can't create antithread on this pool: we're one"); errx(1, "Can't create antithread on this pool: we're one");
/* We don't want this allocated *in* the pool. */ /* We don't want this allocated *in* the pool. */
at = talloc_steal(pool, talloc(NULL, struct athread)); at = talloc_steal(atp, talloc(NULL, struct athread));
if (pipe(p2c) != 0) if (pipe(p2c) != 0)
goto free; goto free;
...@@ -241,19 +301,19 @@ free: ...@@ -241,19 +301,19 @@ free:
} }
/* Creating an antithread via fork() */ /* Creating an antithread via fork() */
struct athread *_at_run(struct at_pool *pool, struct athread *_at_run(struct at_pool *atp,
void *(*fn)(struct at_pool *, void *), void *(*fn)(struct at_pool *, void *),
void *obj) void *obj)
{ {
struct athread *at; struct athread *at;
at = fork_thread(pool); at = fork_thread(atp);
if (!at) if (!at)
return NULL; return NULL;
if (at->pid == 0) { if (at->pid == 0) {
/* Child */ /* Child */
at_tell_parent(pool, fn(pool, obj)); at_tell_parent(atp, fn(atp, obj));
exit(0); exit(0);
} }
/* Parent */ /* Parent */
...@@ -269,12 +329,12 @@ static unsigned int num_args(char *const argv[]) ...@@ -269,12 +329,12 @@ static unsigned int num_args(char *const argv[])
} }
/* Fork and execvp, with added arguments for child to grab. */ /* Fork and execvp, with added arguments for child to grab. */
struct athread *at_spawn(struct at_pool *pool, void *arg, char *cmdline[]) struct athread *at_spawn(struct at_pool *atp, void *arg, char *cmdline[])
{ {
struct athread *at; struct athread *at;
int err; int err;
at = fork_thread(pool); at = fork_thread(atp);
if (!at) if (!at)
return NULL; return NULL;
...@@ -283,15 +343,15 @@ struct athread *at_spawn(struct at_pool *pool, void *arg, char *cmdline[]) ...@@ -283,15 +343,15 @@ struct athread *at_spawn(struct at_pool *pool, void *arg, char *cmdline[])
char *argv[num_args(cmdline) + 2]; char *argv[num_args(cmdline) + 2];
argv[0] = cmdline[0]; argv[0] = cmdline[0];
argv[1] = talloc_asprintf(NULL, "AT:%p/%lu/%i/%i/%i/%p", argv[1] = talloc_asprintf(NULL, "AT:%p/%lu/%i/%i/%i/%p",
pool->pool, pool->poolsize, atp->p->pool, atp->p->poolsize,
pool->fd, pool->parent_rfd, atp->p->fd, atp->p->parent_rfd,
pool->parent_wfd, arg); atp->p->parent_wfd, arg);
/* Copy including NULL terminator. */ /* Copy including NULL terminator. */
memcpy(&argv[2], &cmdline[1], num_args(cmdline)*sizeof(char *)); memcpy(&argv[2], &cmdline[1], num_args(cmdline)*sizeof(char *));
execvp(argv[0], argv); execvp(argv[0], argv);
err = errno; err = errno;
write_all(pool->parent_wfd, &err, sizeof(err)); write_all(atp->p->parent_wfd, &err, sizeof(err));
exit(1); exit(1);
} }
...@@ -344,7 +404,8 @@ void at_tell(struct athread *at, const void *status) ...@@ -344,7 +404,8 @@ void at_tell(struct athread *at, const void *status)
/* For child to grab arguments from command line (removes them) */ /* For child to grab arguments from command line (removes them) */
struct at_pool *at_get_pool(int *argc, char *argv[], void **arg) struct at_pool *at_get_pool(int *argc, char *argv[], void **arg)
{ {
struct at_pool *p = talloc(NULL, struct at_pool); struct at_pool *atp = talloc(NULL, struct at_pool);
struct at_pool_contents *p;
void *map; void *map;
int err; int err;
...@@ -357,6 +418,8 @@ struct at_pool *at_get_pool(int *argc, char *argv[], void **arg) ...@@ -357,6 +418,8 @@ struct at_pool *at_get_pool(int *argc, char *argv[], void **arg)
if (arg == NULL) if (arg == NULL)
arg = &map; arg = &map;
p = atp->p = talloc(atp, struct at_pool_contents);
if (sscanf(argv[1], "AT:%p/%lu/%i/%i/%i/%p", if (sscanf(argv[1], "AT:%p/%lu/%i/%i/%i/%p",
&p->pool, &p->poolsize, &p->fd, &p->pool, &p->poolsize, &p->fd,
&p->parent_rfd, &p->parent_wfd, arg) != 6) { &p->parent_rfd, &p->parent_wfd, arg) != 6) {
...@@ -375,8 +438,13 @@ struct at_pool *at_get_pool(int *argc, char *argv[], void **arg) ...@@ -375,8 +438,13 @@ struct at_pool *at_get_pool(int *argc, char *argv[], void **arg)
goto fail; goto fail;
} }
p->ctx = talloc_add_external(p, at_realloc); list_add(&pools, &p->list);
if (!p->ctx) talloc_set_destructor(p, destroy_pool);
p->atp = atp;
atp->ctx = talloc_add_external(atp,
at_realloc, talloc_lock, talloc_unlock);
if (!atp->ctx)
goto fail; goto fail;
/* Tell parent we're good. */ /* Tell parent we're good. */
...@@ -388,33 +456,33 @@ struct at_pool *at_get_pool(int *argc, char *argv[], void **arg) ...@@ -388,33 +456,33 @@ struct at_pool *at_get_pool(int *argc, char *argv[], void **arg)
/* Delete AT arg. */ /* Delete AT arg. */
memmove(&argv[1], &argv[2], --(*argc)); memmove(&argv[1], &argv[2], --(*argc));
return p;
return atp;
fail: fail:
/* FIXME: cleanup properly. */ talloc_free(atp);
talloc_free(p);
return NULL; return NULL;
} }
/* Say something to our parent (async). */ /* Say something to our parent (async). */
void at_tell_parent(struct at_pool *pool, const void *status) void at_tell_parent(struct at_pool *atp, const void *status)
{ {
if (pool->parent_wfd == -1) if (atp->p->parent_wfd == -1)
errx(1, "This process is not an antithread of this pool"); errx(1, "This process is not an antithread of this pool");
if (write(pool->parent_wfd, &status, sizeof(status)) != sizeof(status)) if (write(atp->p->parent_wfd, &status, sizeof(status))!=sizeof(status))
err(1, "Failure writing to parent"); err(1, "Failure writing to parent");
} }
/* What's the parent saying? Blocks if fd not ready. */ /* What's the parent saying? Blocks if fd not ready. */
void *at_read_parent(struct at_pool *pool) void *at_read_parent(struct at_pool *atp)
{ {
void *ret; void *ret;
if (pool->parent_rfd == -1) if (atp->p->parent_rfd == -1)
errx(1, "This process is not an antithread of this pool"); errx(1, "This process is not an antithread of this pool");
switch (read(pool->parent_rfd, &ret, sizeof(ret))) { switch (read(atp->p->parent_rfd, &ret, sizeof(ret))) {
case -1: case -1:
err(1, "Reading from parent"); err(1, "Reading from parent");
case 0: case 0:
...@@ -429,18 +497,18 @@ void *at_read_parent(struct at_pool *pool) ...@@ -429,18 +497,18 @@ void *at_read_parent(struct at_pool *pool)
} }
/* The fd to poll on */ /* The fd to poll on */
int at_parent_fd(struct at_pool *pool) int at_parent_fd(struct at_pool *atp)
{ {
if (pool->parent_rfd == -1) if (atp->p->parent_rfd == -1)
errx(1, "This process is not an antithread of this pool"); errx(1, "This process is not an antithread of this pool");
return pool->parent_rfd; return atp->p->parent_rfd;
} }
/* FIXME: Futexme. */ /* FIXME: Futexme. */
void at_lock(void *obj) void at_lock(void *obj)
{ {
struct at_pool *p = talloc_find_parent_bytype(obj, struct at_pool); struct at_pool *atp = talloc_find_parent_bytype(obj, struct at_pool);
#if 0 #if 0
unsigned int *l; unsigned int *l;
...@@ -448,7 +516,7 @@ void at_lock(void *obj) ...@@ -448,7 +516,7 @@ void at_lock(void *obj)
l = talloc_lock_ptr(obj); l = talloc_lock_ptr(obj);
#endif #endif
lock(p->fd, (char *)obj - (char *)p->pool); lock(atp->p->fd, (char *)obj - (char *)atp->p->pool);
#if 0 #if 0
if (*l) if (*l)
...@@ -459,7 +527,7 @@ void at_lock(void *obj) ...@@ -459,7 +527,7 @@ void at_lock(void *obj)
void at_unlock(void *obj) void at_unlock(void *obj)
{ {
struct at_pool *p = talloc_find_parent_bytype(obj, struct at_pool); struct at_pool *atp = talloc_find_parent_bytype(obj, struct at_pool);
#if 0 #if 0
unsigned int *l; unsigned int *l;
...@@ -468,15 +536,15 @@ void at_unlock(void *obj) ...@@ -468,15 +536,15 @@ void at_unlock(void *obj)
errx(1, "Object %p was already unlocked", obj); errx(1, "Object %p was already unlocked", obj);
*l = 0; *l = 0;
#endif #endif
unlock(p->fd, (char *)obj - (char *)p->pool); unlock(atp->p->fd, (char *)obj - (char *)atp->p->pool);
} }
void at_lock_all(struct at_pool *p) void at_lock_all(struct at_pool *atp)
{ {
lock(p->fd, 0); lock(atp->p->fd, 0);
} }
void at_unlock_all(struct at_pool *p) void at_unlock_all(struct at_pool *atp)
{ {
unlock(p->fd, 0); unlock(atp->p->fd, 0);
} }
...@@ -20,8 +20,8 @@ int main(int argc, char *argv[]) ...@@ -20,8 +20,8 @@ int main(int argc, char *argv[])
assert(atp); assert(atp);
pid = talloc(at_pool_ctx(atp), int); pid = talloc(at_pool_ctx(atp), int);
assert(pid); assert(pid);
ok1((char *)pid >= (char *)atp->pool ok1((char *)pid >= (char *)atp->p->pool
&& (char *)pid < (char *)atp->pool + atp->poolsize); && (char *)pid < (char *)atp->p->pool + atp->p->poolsize);
at = at_run(atp, test, pid); at = at_run(atp, test, pid);
assert(at); assert(at);
......
...@@ -26,8 +26,8 @@ int main(int argc, char *argv[]) ...@@ -26,8 +26,8 @@ int main(int argc, char *argv[])
assert(atp); assert(atp);
pid = talloc(at_pool_ctx(atp), int); pid = talloc(at_pool_ctx(atp), int);
assert(pid); assert(pid);
ok1((char *)pid >= (char *)atp->pool ok1((char *)pid >= (char *)atp->p->pool
&& (char *)pid < (char *)atp->pool + atp->poolsize); && (char *)pid < (char *)atp->p->pool + atp->p->poolsize);
/* This is a failed spawn. */ /* This is a failed spawn. */
at = at_spawn(atp, pid, bad_args); at = at_spawn(atp, pid, bad_args);
......
...@@ -21,8 +21,8 @@ int main(int argc, char *argv[]) ...@@ -21,8 +21,8 @@ int main(int argc, char *argv[])
assert(atp); assert(atp);
pid = talloc(at_pool_ctx(atp), int); pid = talloc(at_pool_ctx(atp), int);
assert(pid); assert(pid);
ok1((char *)pid >= (char *)atp->pool ok1((char *)pid >= (char *)atp->p->pool
&& (char *)pid < (char *)atp->pool + atp->poolsize); && (char *)pid < (char *)atp->p->pool + atp->p->poolsize);
at = at_run(atp, test, pid); at = at_run(atp, test, pid);
assert(at); assert(at);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment