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(¬ifier_lock); + write_lock_nocancel(¬ifier_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(¬ifier_lock); - lock_notifier_list(&oset); + lock_notifier_list(&set); pvlist_append(&nf->link, ¬ifier_list); - unlock_notifier_list(&oset); + unlock_notifier_list(&set); pop_cleanup_lock(¬ifier_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(¬ifier_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 = ¬ifier_sighandler; sa.sa_flags = SA_SIGINFO|SA_RESTART; - sigaction(SIGNOTIFY, &sa, ¬ifier_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