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

Author: Philippe Gerum <r...@xenomai.org>
Date:   Wed May  7 18:12:07 2014 +0200

copperplate/notifier: enable notifying remote threads

In shared multi-processing mode, we may have to suspend/resume threads
which belong to sibling processes from the same Copperplate session.

To this end, the process-local pipe() is replaced by a signalfd
descriptor associated to the dedicated SIGRESM signal, which we read
from when waiting for the wake up call. Such call is issued via the
tkill(2) interface, to make sure it is queued for the proper thread
(i.e. no fallback delivery to a member of the same thread group).

---

 include/copperplate/notifier.h       |    2 +-
 include/mercury/boilerplate/signal.h |    9 ++---
 lib/copperplate/notifier.c           |   63 +++++++++++++++++-----------------
 3 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/include/copperplate/notifier.h b/include/copperplate/notifier.h
index 61e2ec4..0518477 100644
--- a/include/copperplate/notifier.h
+++ b/include/copperplate/notifier.h
@@ -23,7 +23,7 @@
 
 struct notifier {
        pid_t owner;
-       int waitfd[2];
+       int sigfd;
        struct pvholder link;
 };
 
diff --git a/include/mercury/boilerplate/signal.h 
b/include/mercury/boilerplate/signal.h
index df131fa..914c02c 100644
--- a/include/mercury/boilerplate/signal.h
+++ b/include/mercury/boilerplate/signal.h
@@ -24,15 +24,16 @@
 #define sigev_notify_thread_id  _sigev_un._tid
 #endif
 
-#define SIGNOTIFY      (SIGRTMIN + 8) /* Internal notification */
-#define SIGRELS                (SIGRTMIN + 9) /* Syscall abort */
-#define SIGRRB         (SIGRTMIN + 10) /* Round-robin event */
+#define SIGSUSP                (SIGRTMIN + 8)
+#define SIGRESM                (SIGRTMIN + 9)
+#define SIGRELS                (SIGRTMIN + 10) /* Syscall abort */
+#define SIGRRB         (SIGRTMIN + 11) /* Round-robin event */
 
 #define SIGSAFE_LOCK_ENTRY(__safelock)                                 \
        do {                                                            \
                sigset_t __safeset, __oldsafeset;                       \
                sigemptyset(&__safeset);                                \
-               sigaddset(&__safeset, SIGNOTIFY);                       \
+               sigaddset(&__safeset, SIGSUSP);                         \
                pthread_sigmask(SIG_BLOCK, &__safeset, &__oldsafeset);  \
                push_cleanup_lock(__safelock);                          \
                write_lock(__safelock);
diff --git a/lib/copperplate/notifier.c b/lib/copperplate/notifier.c
index 0e8c832..45b3c9a 100644
--- a/lib/copperplate/notifier.c
+++ b/lib/copperplate/notifier.c
@@ -16,6 +16,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
  */
 
+#include <sys/signalfd.h>
 #include <signal.h>
 #include <memory.h>
 #include <unistd.h>
@@ -32,8 +33,6 @@ static DEFINE_PRIVATE_LIST(notifier_list);
 
 static pthread_mutex_t notifier_lock;
 
-static struct sigaction notifier_old_sa;
-
 static void notifier_sighandler(int sig, siginfo_t *siginfo, void *uc)
 {
        struct notifier *nf;
@@ -61,10 +60,18 @@ static void lock_notifier_list(sigset_t *oset)
 {
        sigset_t set;
 
+       /*
+        * We want to defer the SIGSUSP delivery until the list is
+        * unlocked, so that notifier_sighandler() will always see a
+        * consistent linkage when traversing such list. Since the
+        * signal handler and the lock holder always run on the same
+        * process, we may use a private list, and the synchronization
+        * mechanism is inherently SMP-safe. Yummie.
+        */
        sigemptyset(&set);
-       sigaddset(&set, SIGNOTIFY);
+       sigaddset(&set, SIGSUSP);
        pthread_sigmask(SIG_BLOCK, &set, oset);
-       write_lock(&notifier_lock);
+       write_lock_nocancel(&notifier_lock);
 }
 
 static void unlock_notifier_list(sigset_t *oset)
@@ -75,27 +82,24 @@ static void unlock_notifier_list(sigset_t *oset)
 
 int notifier_init(struct notifier *nf, pid_t pid)
 {
-       sigset_t oset;
-       int ret;
+       sigset_t set;
 
-       if (pipe(nf->waitfd) < 0) {
-               ret = -errno;
-               goto fail;
-       }
+       sigemptyset(&set);
+       sigaddset(&set, SIGRESM);
+       nf->sigfd = signalfd(-1, &set, SFD_CLOEXEC);
+       if (nf->sigfd < 0)
+               return __bt(-errno);
 
        nf->owner = pid;
+       pthread_sigmask(SIG_BLOCK, &set, NULL);
 
        push_cleanup_lock(&notifier_lock);
-       lock_notifier_list(&oset);
+       lock_notifier_list(&set);
        pvlist_append(&nf->link, &notifier_list);
-       unlock_notifier_list(&oset);
+       unlock_notifier_list(&set);
        pop_cleanup_lock(&notifier_lock);
 
        return 0;
-fail:
-       warning("failed to create notifier pipe");
-
-       return __bt(ret);
 }
 
 void notifier_destroy(struct notifier *nf)
@@ -107,38 +111,32 @@ void notifier_destroy(struct notifier *nf)
        pvlist_remove(&nf->link);
        unlock_notifier_list(&oset);
        pop_cleanup_lock(&notifier_lock);
-       close(nf->waitfd[0]); /* May fail if disabled. */
-       close(nf->waitfd[1]);
+       close(nf->sigfd); /* May fail if disabled. */
 }
 
 void notifier_signal(struct notifier *nf)
 {
-       copperplate_kill_tid(nf->owner, SIGNOTIFY);
+       copperplate_kill_tid(nf->owner, SIGSUSP);
 }
 
-void notifier_disable(struct notifier *nf)
+void notifier_release(struct notifier *nf)
 {
-       close(nf->waitfd[0]);
+       copperplate_kill_tid(nf->owner, SIGRESM);
 }
 
-void notifier_release(struct notifier *nf)
+void notifier_wait(const struct notifier *nf)
 {
-       char c = 1;
+       struct signalfd_siginfo ssi;
        int ret;
 
        do
-               ret = write(nf->waitfd[1], &c, 1);
+               ret = read(nf->sigfd, &ssi, sizeof(ssi));
        while (ret == -1 && errno == EINTR);
 }
 
-void notifier_wait(const struct notifier *nf)
+void notifier_disable(struct notifier *nf)
 {
-       int ret;
-       char c;
-
-       do
-               ret = read(nf->waitfd[0], &c, 1);
-       while (ret == -1 && errno == EINTR);
+       close(nf->sigfd);
 }
 
 void notifier_pkg_init(void)
@@ -168,5 +166,6 @@ void notifier_pkg_init(void)
        memset(&sa, 0, sizeof(sa));
        sa.sa_sigaction = &notifier_sighandler;
        sa.sa_flags = SA_SIGINFO|SA_RESTART;
-       sigaction(SIGNOTIFY, &sa, &notifier_old_sa);
+       sigaction(SIGSUSP, &sa, NULL);
+       sigaction(SIGRESM, &sa, NULL);
 }


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to