Module: xenomai-3
Branch: next
Commit: f4c48dda31d4ec70a655245a8e1b093c92060844
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=f4c48dda31d4ec70a655245a8e1b093c92060844

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     |    7 ++++
 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, 138 insertions(+), 90 deletions(-)

diff --git a/include/copperplate/heapobj.h b/include/copperplate/heapobj.h
index c92e581..b628ea4 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);
@@ -425,6 +427,11 @@ static inline int heapobj_bind_session(const char *session)
        return -ENOSYS;
 }
 
+static inline int heapobj_unlink_session(const char *session)
+{
+       return 0;
+}
+
 static inline void heapobj_unbind_session(void) { }
 
 static inline void *xnmalloc(size_t size)
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(&regflags);
        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

Reply via email to