Module: xenomai-3 Branch: next Commit: 58549fe7df89c3871d11e9f1ba50cbec9e80fa3f URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=58549fe7df89c3871d11e9f1ba50cbec9e80fa3f
Author: Philippe Gerum <r...@xenomai.org> Date: Sun Mar 22 19:21:29 2015 +0100 copperplate/heapobj: use per-process heap for anon sessions We have different lifetimes for Cobalt-managed POSIX objects such as mutexes and condvars, and Cobalt maintains dynamically allocated resources for them. Some POSIX objects are embedded into the session header for protecting sysgroups, and serializing allocation ops on the shared heap. Therefore, they must survive until the last process detaches from the anon session. Most other POSIX objects stored into the shared heap become virtually stale when the application exits and should be reclaimed automatically, so that we don't end up leaking kernel resources as processes come and go into the anon session. For the sake of simplicity, Cobalt reclaims shared POSIX objects upon exit of their respective creator, assuming that a multi-process application requires all involved processes to be present at any time, including the one which has initialized the resources. By using separate, per-process heaps for each instance of the anon session, we make sure that all POSIX resources can be reclaimed safely by Cobalt for any given session, upon application exit. --- include/copperplate/heapobj.h | 2 ++ include/copperplate/registry.h | 12 +++++-- lib/copperplate/heapobj-pshared.c | 39 ++++++++++++++++------ lib/copperplate/init.c | 38 ++++++++++++++-------- lib/copperplate/internal.h | 3 +- lib/copperplate/regd/regd.c | 65 +++++++++++++++++++++++-------------- lib/copperplate/registry.c | 42 +++++++++++++++--------- scripts/xeno-multiuser | 22 ++----------- 8 files changed, 133 insertions(+), 90 deletions(-) diff --git a/include/copperplate/heapobj.h b/include/copperplate/heapobj.h index c92e581..2660eae 100644 --- a/include/copperplate/heapobj.h +++ b/include/copperplate/heapobj.h @@ -310,6 +310,8 @@ int heapobj_bind_session(const char *session); void heapobj_unbind_session(void); +int heapobj_unlink_session(const char *session); + void *xnmalloc(size_t size); void xnfree(void *ptr); diff --git a/include/copperplate/registry.h b/include/copperplate/registry.h index 903db4a..7b5fa4a 100644 --- a/include/copperplate/registry.h +++ b/include/copperplate/registry.h @@ -29,6 +29,9 @@ struct fsobj; +#define REGISTRY_SHARED 1 +#define REGISTRY_ANON 2 + #ifdef CONFIG_XENO_REGISTRY struct registry_operations { @@ -76,9 +79,12 @@ void registry_destroy_file(struct fsobj *fsobj); void registry_touch_file(struct fsobj *fsobj); -int __registry_pkg_init(const char *arg0, char *mountpt, int shared_registry); +int __registry_pkg_init(const char *arg0, + char *mountpt, + int flags); -int registry_pkg_init(const char *arg0); +int registry_pkg_init(const char *arg0, + int flags); void registry_pkg_destroy(void); @@ -126,7 +132,7 @@ void registry_touch_file(struct fsobj *fsobj) } static inline -int __registry_pkg_init(const char *arg0, char *mountpt, int shared_registry) +int __registry_pkg_init(const char *arg0, char *mountpt, int flags) { return 0; } diff --git a/lib/copperplate/heapobj-pshared.c b/lib/copperplate/heapobj-pshared.c index 20b5b44..88c0e21 100644 --- a/lib/copperplate/heapobj-pshared.c +++ b/lib/copperplate/heapobj-pshared.c @@ -33,6 +33,7 @@ #include <unistd.h> #include <signal.h> #include <fcntl.h> +#include <malloc.h> #include <unistd.h> #include "boilerplate/list.h" #include "boilerplate/hash.h" @@ -622,7 +623,7 @@ static int create_main_heap(pid_t *cnode_r) * Otherwise, create the heap for the new emerging session and * bind to it. */ - snprintf(hobj->name, sizeof(hobj->name), "%s.main-heap", session); + snprintf(hobj->name, sizeof(hobj->name), "%s.heap", session); snprintf(hobj->fsname, sizeof(hobj->fsname), "/xeno:%s", hobj->name); fd = shm_open(hobj->fsname, O_RDWR|O_CREAT, 0600); @@ -708,13 +709,13 @@ static int bind_main_heap(const char *session) { struct heapobj *hobj = &main_pool; struct session_heap *m_heap; + int ret, fd, cpid; struct stat sbuf; memoff_t len; - int ret, fd; /* No error tracking, this is for internal users. */ - snprintf(hobj->name, sizeof(hobj->name), "%s.main-heap", session); + snprintf(hobj->name, sizeof(hobj->name), "%s.heap", session); snprintf(hobj->fsname, sizeof(hobj->fsname), "/xeno:%s", hobj->name); fd = shm_open(hobj->fsname, O_RDWR, 0400); @@ -739,9 +740,10 @@ static int bind_main_heap(const char *session) if (m_heap == MAP_FAILED) goto errno_fail; + cpid = m_heap->cpid; __STD(close(fd)); - if (m_heap->cpid == 0 || kill(m_heap->cpid, 0)) { + if (cpid == 0 || kill(cpid, 0)) { munmap(m_heap, len); return -ENOENT; } @@ -855,20 +857,23 @@ void heapobj_destroy(struct heapobj *hobj) struct shared_heap *heap = hobj->pool; int cpid; - __RT(pthread_mutex_destroy(&heap->lock)); - if (hobj != &main_pool) { + __RT(pthread_mutex_destroy(&heap->lock)); sysgroup_remove(heap, &heap->memspec); free_block(&main_heap.base, heap); return; } - __RT(pthread_mutex_destroy(&main_heap.sysgroup.lock)); cpid = main_heap.cpid; + if (cpid != get_thread_pid() && kill(cpid, 0) == 0) { + munmap(&main_heap, main_heap.maplen); + return; + } + + __RT(pthread_mutex_destroy(&heap->lock)); + __RT(pthread_mutex_destroy(&main_heap.sysgroup.lock)); munmap(&main_heap, main_heap.maplen); - - if (cpid == get_thread_pid() || (cpid && kill(cpid, 0))) - shm_unlink(hobj->fsname); + shm_unlink(hobj->fsname); } int heapobj_extend(struct heapobj *hobj, size_t size, void *unused) @@ -965,3 +970,17 @@ void heapobj_unbind_session(void) munmap(&main_heap, len); } + +int heapobj_unlink_session(const char *session) +{ + char *path; + int ret; + + ret = asprintf(&path, "/xeno:%s.heap", session); + if (ret < 0) + return -ENOMEM; + ret = shm_unlink(path) ? -errno : 0; + free(path); + + return ret; +} diff --git a/lib/copperplate/init.c b/lib/copperplate/init.c index 32a31aa..b5b7a36 100644 --- a/lib/copperplate/init.c +++ b/lib/copperplate/init.c @@ -478,7 +478,7 @@ static int parse_skin_options(int *argcp, int largc, char **uargv, * __node_info. */ void copperplate_bootstrap_minimal(const char *arg0, char *mountpt, - int shared_registry) + int regflags) { int ret; @@ -498,7 +498,7 @@ void copperplate_bootstrap_minimal(const char *arg0, char *mountpt, goto fail; } - ret = __registry_pkg_init(arg0, mountpt, shared_registry); + ret = __registry_pkg_init(arg0, mountpt, regflags); if (ret) goto fail; @@ -507,34 +507,44 @@ fail: early_panic("initialization failed, %s", symerror(ret)); } -static int get_session_root(void) +static int get_session_root(int *regflags_r) { + char *sessdir, *session; struct passwd *pw; - char *sessdir; int ret; - if (__node_info.session_label) { + if (__node_info.session_label == NULL) { + ret = asprintf(&session, "anon@%d", __node_id); + if (ret < 0) + return -ENOMEM; + __node_info.session_label = session; + ret = asprintf(&sessdir, "%s/%s", + __node_info.registry_root, session); + if (ret < 0) + return -ENOMEM; + *regflags_r |= REGISTRY_ANON; + } else { pw = getpwuid(geteuid()); if (pw == NULL) return -errno; - ret = asprintf(&sessdir, "%s/%s/%s", __node_info.registry_root, + + ret = asprintf(&sessdir, "%s/%s/%s", + __node_info.registry_root, pw->pw_name, __node_info.session_label); - } else { - __node_info.session_label = DEFAULT_REGISTRY_SESSION; - ret = asprintf(&sessdir, "%s/%s", __node_info.registry_root, - DEFAULT_REGISTRY_SESSION); + if (ret < 0) + return -ENOMEM; } __node_info.session_root = sessdir; - return ret < 0 ? -ENOMEM : 0; + return 0; } /* The application-level copperplate init call. */ void copperplate_init(int *argcp, char *const **argvp) { - int ret, largc, base_opt_start; + int ret, largc, base_opt_start, regflags = 0; struct copperskin *skin; struct option *options; static int init_done; @@ -604,7 +614,7 @@ void copperplate_init(int *argcp, char *const **argvp) * We need the session label to be known before we create the * shared heap, which is named after the former. */ - ret = get_session_root(); + ret = get_session_root(®flags); if (ret) goto fail; @@ -615,7 +625,7 @@ void copperplate_init(int *argcp, char *const **argvp) } if (__node_info.no_registry == 0) { - ret = registry_pkg_init(uargv[0]); + ret = registry_pkg_init(uargv[0], regflags); if (ret) goto fail; } diff --git a/lib/copperplate/internal.h b/lib/copperplate/internal.h index ed176b2..7f42e86 100644 --- a/lib/copperplate/internal.h +++ b/lib/copperplate/internal.h @@ -35,7 +35,6 @@ #else #define DEFAULT_REGISTRY_ROOT NULL #endif -#define DEFAULT_REGISTRY_SESSION "anon" struct coppernode { unsigned int mem_pool; @@ -113,7 +112,7 @@ int copperplate_renice_local_thread(pthread_t ptid, int policy, const struct sched_param_ex *param_ex); void copperplate_bootstrap_minimal(const char *arg0, - char *mountpt, int shared_registry); + char *mountpt, int regflags); #ifdef __cplusplus } diff --git a/lib/copperplate/regd/regd.c b/lib/copperplate/regd/regd.c index a767592..18915cd 100644 --- a/lib/copperplate/regd/regd.c +++ b/lib/copperplate/regd/regd.c @@ -42,7 +42,7 @@ #define note(fmt, args...) \ do { \ if (!daemonize) \ - printf("regd: " fmt "\n", ##args); \ + printf("sysregd: " fmt "\n", ##args); \ } while (0) static char *rootdir; @@ -57,6 +57,8 @@ static int linger; static int shared; +static int anon; + struct client { char *mountpt; int sockfd; @@ -67,10 +69,11 @@ static DEFINE_PRIVATE_LIST(client_list); static void usage(void) { - fprintf(stderr, "usage: regd [--root=<dir>] set registry root directory\n"); - fprintf(stderr, " [--shared] share registry between different users\n"); - fprintf(stderr, " [--daemonize] run in the background\n"); - fprintf(stderr, " [--linger] disable timed exit on idleness\n"); + fprintf(stderr, "usage: sysregd --root=<dir> set registry root directory\n"); + fprintf(stderr, " [--shared] share registry between different users\n"); + fprintf(stderr, " [--anon] mount registry for anonymous session\n"); + fprintf(stderr, " [--daemonize] run in the background\n"); + fprintf(stderr, " [--linger] disable timed exit on idleness\n"); } static const struct option options[] = { @@ -108,6 +111,13 @@ static const struct option options[] = { .val = 1, }, { +#define anon_opt 5 + .name = "anon", + .has_arg = 0, + .flag = &anon, + .val = 1, + }, + { .name = NULL, }, }; @@ -306,6 +316,7 @@ static void unregister_client(int s) static void delete_system_fs(void) { + note("unmounting %s", sysroot); unmount(sysroot); rmdir(sysroot); rmdir(rootdir); @@ -313,16 +324,16 @@ static void delete_system_fs(void) static void handle_requests(void) { + int ret, s, tmfd = -1; struct itimerspec its; fd_set refset, set; - int ret, s, tmfd = -1; uint64_t exp; char c; FD_ZERO(&refset); FD_SET(sockfd, &refset); - if (!linger) { + if (!(linger || anon)) { tmfd = __STD(timerfd_create(CLOCK_MONOTONIC, 0)); if (tmfd < 0) error(1, errno, "handle_requests/timerfd_create"); @@ -350,10 +361,10 @@ static void handle_requests(void) continue; } FD_SET(s, &refset); - if (!linger) + if (tmfd != -1) __STD(timerfd_settime(tmfd, 0, &its, NULL)); } - if (!linger && FD_ISSET(tmfd, &set)) { + if (tmfd != -1 && FD_ISSET(tmfd, &set)) { ret = __STD(read(tmfd, &exp, sizeof(exp))); (void)ret; if (pvlist_empty(&client_list)) { @@ -369,6 +380,15 @@ static void handle_requests(void) unregister_client(s); __STD(close(s)); FD_CLR(s, &refset); + if (anon && pvlist_empty(&client_list)) { + delete_system_fs(); + if (daemonize) { + note("unlinking session %s", + __node_info.session_label); + heapobj_unlink_session(__node_info.session_label); + } + exit(0); + } } } } @@ -380,7 +400,7 @@ static void cleanup_handler(int sig) _exit(1); } -static void create_system_fs(const char *arg0, const char *rootdir) +static void create_system_fs(const char *arg0, const char *rootdir, int flags) { struct sysreg_fsfile *f; struct sysreg_fsdir *d; @@ -422,7 +442,7 @@ bootstrap: __node_info.session_label = session; __node_info.registry_root = rootdir; sysroot = mountpt; - copperplate_bootstrap_minimal(arg0, mountpt, shared); + copperplate_bootstrap_minimal(arg0, mountpt, flags); note("mounted system fs at %s", mountpt); @@ -446,8 +466,7 @@ bootstrap: int main(int argc, char *const *argv) { - struct passwd *pw = NULL; - int lindex, opt, ret; + int lindex, opt, ret, flags = 0; struct sigaction sa; for (;;) { @@ -461,7 +480,12 @@ int main(int argc, char *const *argv) return 0; case daemonize_opt: case linger_opt: + break; case shared_opt: + flags |= REGISTRY_SHARED; + break; + case anon_opt: + flags |= REGISTRY_ANON; break; case root_opt: rootdir = optarg; @@ -472,17 +496,8 @@ int main(int argc, char *const *argv) } } - if (rootdir == NULL) { - pw = getpwuid(geteuid()); - if (!pw) - return -errno; - ret = asprintf(&rootdir, "%s/%s/%s", - DEFAULT_REGISTRY_ROOT, - pw->pw_name, - DEFAULT_REGISTRY_SESSION); - if (ret < 0) - return -ENOMEM; - } + if (rootdir == NULL) + error(1, EINVAL, "--root must be given"); memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; @@ -497,7 +512,7 @@ int main(int argc, char *const *argv) create_rootdir(); bind_socket(); - create_system_fs(argv[0], rootdir); + create_system_fs(argv[0], rootdir, flags); handle_requests(); return 0; diff --git a/lib/copperplate/registry.c b/lib/copperplate/registry.c index cc10464..26b777b 100644 --- a/lib/copperplate/registry.c +++ b/lib/copperplate/registry.c @@ -60,7 +60,7 @@ static pthread_t regfs_thid; struct regfs_data { const char *arg0; char *mountpt; - int shared; + int flags; sem_t sync; int status; pthread_mutex_t lock; @@ -594,8 +594,9 @@ static void *registry_thread(void *arg) av[2] = "-f"; av[3] = p->mountpt; av[4] = "-o"; - av[5] = p->shared ? "default_permissions,allow_other" - : "default_permissions"; + av[5] = p->flags & REGISTRY_SHARED ? + "default_permissions,allow_other" + : "default_permissions"; av[6] = NULL; /* @@ -624,14 +625,14 @@ static void sigchld_handler(int sig) regd_pid = 0; } -static int spawn_daemon(const char *sessdir) +static int spawn_daemon(const char *sessdir, int flags) { struct sigaction sa; - char *exec_path; + char *path, *av[6]; pid_t pid; int ret; - ret = asprintf(&exec_path, "%s/sbin/sysregd", CONFIG_XENO_PREFIX); + ret = asprintf(&path, "%s/sbin/sysregd", CONFIG_XENO_PREFIX); if (ret < 0) return -ENOMEM; @@ -654,11 +655,20 @@ static int spawn_daemon(const char *sessdir) sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); + av[0] = "sysregd"; + av[1] = "--daemon"; + av[2] = "--root"; + av[3] = (char *)sessdir; + if (flags & REGISTRY_ANON) { + av[4] = "--anon"; + av[5] = NULL; + } else + av[4] = NULL; + pid = vfork(); switch (pid) { case 0: - execl(exec_path, "sysregd", "--daemon", - "--root", sessdir, NULL); + execv(path, av); _exit(1); case -1: sa.sa_handler = SIG_DFL; @@ -680,12 +690,12 @@ static int spawn_daemon(const char *sessdir) break; } - free(exec_path); + free(path); return ret; } -static int connect_regd(const char *sessdir, char **mountpt) +static int connect_regd(const char *sessdir, char **mountpt, int flags) { struct sockaddr_un sun; int s, ret, retries; @@ -717,7 +727,7 @@ static int connect_regd(const char *sessdir, char **mountpt) return 0; } close(s); - ret = spawn_daemon(sessdir); + ret = spawn_daemon(sessdir, flags); if (ret) break; ret = -EAGAIN; @@ -735,7 +745,7 @@ static void pkg_cleanup(void) registry_pkg_destroy(); } -int __registry_pkg_init(const char *arg0, char *mountpt, int shared_registry) +int __registry_pkg_init(const char *arg0, char *mountpt, int flags) { struct regfs_data *p = regfs_get_context(); pthread_mutexattr_t mattr; @@ -767,7 +777,7 @@ int __registry_pkg_init(const char *arg0, char *mountpt, int shared_registry) pthread_attr_setscope(&thattr, PTHREAD_SCOPE_PROCESS); p->arg0 = arg0; p->mountpt = mountpt; - p->shared = shared_registry; + p->flags = flags; p->status = -EINVAL; __STD(sem_init(&p->sync, 0, 0)); @@ -799,16 +809,16 @@ int __registry_pkg_init(const char *arg0, char *mountpt, int shared_registry) return p->status; } -int registry_pkg_init(const char *arg0) +int registry_pkg_init(const char *arg0, int flags) { char *mountpt; int ret; - ret = connect_regd(__node_info.session_root, &mountpt); + ret = connect_regd(__node_info.session_root, &mountpt, flags); if (ret) return ret; - return __bt(__registry_pkg_init(arg0, mountpt, 0)); + return __bt(__registry_pkg_init(arg0, mountpt, flags)); } void registry_pkg_destroy(void) diff --git a/scripts/xeno-multiuser b/scripts/xeno-multiuser index 5f4d380..643a630 100755 --- a/scripts/xeno-multiuser +++ b/scripts/xeno-multiuser @@ -20,46 +20,28 @@ PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="Xenomai multi-user setup" NAME=xenomai -DAEMON=/usr/sbin/sysregd -DAEMON_ARGS="--linger --shared" -PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME SYSREG_ROOT=/var/run/xenomai XENOMAI_GROUP=xenomai -# Exit if the package is not installed -[ -x "$DAEMON" ] || exit 0 - . /lib/lsb/init-functions do_start() { - pidofproc -p $PIDFILE "$DAEMON" >/dev/null && return 0 - echo `getent group $XENOMAI_GROUP | cut -d: -f3` > /sys/module/xenomai/parameters/allowed_group mkdir -p $SYSREG_ROOT chgrp $XENOMAI_GROUP $SYSREG_ROOT chmod g+rwxs $SYSREG_ROOT - sg $XENOMAI_GROUP -c " - $DAEMON $DAEMON_ARGS --root=$SYSREG_ROOT/anon & - [ \$? == 0 ] || return 1; - echo \$! > $PIDFILE - " - return $? + return 0 } do_stop() { - killproc -p $PIDFILE $DAEMON - RETVAL="$?" - rm -f $PIDFILE # Clean up mountpoint root dir rm -rf $SYSREG_ROOT - - [ "$RETVAL" == 0 ] || return 1 return 0 } @@ -71,7 +53,7 @@ case "$1" in do_stop ;; status) - pidofproc -p $PIDFILE "$DAEMON" >/dev/null && exit 0 || exit $? + exit 0 ;; restart|force-reload) do_stop _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git