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

Author: Philippe Gerum <r...@xenomai.org>
Date:   Wed Sep 11 16:41:47 2013 +0200

cobalt/signal: implement thread group sending

When a signal is sent via the kill() interface and the destination
thread is not waiting for that signal, we try to deliver it to any of
the threads which belong to the same process. If no thread is waiting
for this signal, it is queued for the destination thread as usual.

This change does not affect the behavior of pthread_kill(), which
remains strictly thread-targeted.

---

 kernel/cobalt/posix/mqueue.c  |    2 +-
 kernel/cobalt/posix/process.h |    1 +
 kernel/cobalt/posix/signal.c  |   51 ++++++++++++++++++++++++++++++----------
 kernel/cobalt/posix/signal.h  |    6 +++-
 kernel/cobalt/posix/syscall.c |    2 +
 kernel/cobalt/posix/thread.c  |   22 +++++++++++++----
 kernel/cobalt/posix/thread.h  |    4 +++
 7 files changed, 67 insertions(+), 21 deletions(-)

diff --git a/kernel/cobalt/posix/mqueue.c b/kernel/cobalt/posix/mqueue.c
index fe34fea..354ba19 100644
--- a/kernel/cobalt/posix/mqueue.c
+++ b/kernel/cobalt/posix/mqueue.c
@@ -623,7 +623,7 @@ cobalt_mq_finish_send(mqd_t fd, cobalt_mq_t *mq, struct 
cobalt_msg *msg)
                sigp = cobalt_signal_alloc();
                if (sigp) {
                        cobalt_copy_siginfo(SI_MESGQ, &sigp->si, &mq->si);
-                       cobalt_signal_send(mq->target, sigp);
+                       cobalt_signal_send(mq->target, sigp, 0);
                        resched = 1;
                }
                mq->target = NULL;
diff --git a/kernel/cobalt/posix/process.h b/kernel/cobalt/posix/process.h
index 121a802..42f3afd 100644
--- a/kernel/cobalt/posix/process.h
+++ b/kernel/cobalt/posix/process.h
@@ -36,6 +36,7 @@ struct cobalt_process {
        struct list_head uqds;
        struct list_head usems;
        struct xnshadow_ppd ppd;
+       struct list_head sigwaiters;
 };
 
 extern struct cobalt_kqueues cobalt_global_kqueues;
diff --git a/kernel/cobalt/posix/signal.c b/kernel/cobalt/posix/signal.c
index 6a4199a..aa37f50 100644
--- a/kernel/cobalt/posix/signal.c
+++ b/kernel/cobalt/posix/signal.c
@@ -39,8 +39,9 @@ static LIST_HEAD(sigpending_pool);
                         (_NSIG + (SIGRTMAX - SIGRTMIN) * 2))
 
 static int cobalt_signal_deliver(struct cobalt_thread *thread,
-                                struct cobalt_sigpending *sigp)
-{
+                                struct cobalt_sigpending *sigp,
+                                int group)
+{                              /* nklocked, IRQs off */
        struct cobalt_sigwait_context *swc;
        struct xnthread_wait_context *wc;
        int sig, ret;
@@ -48,18 +49,39 @@ static int cobalt_signal_deliver(struct cobalt_thread 
*thread,
        sig = sigp->si.si_signo;
        XENO_BUGON(COBALT, sig < 1 || sig > _NSIG);
 
-       if (!xnsynch_pended_p(&thread->sigwait))
-               return 0;
+       /*
+        * Attempt to deliver the signal immediately to the initial
+        * target that waits for it.
+        */
+       if (xnsynch_pended_p(&thread->sigwait)) {
+               wc = xnthread_get_wait_context(&thread->threadbase);
+               swc = container_of(wc, struct cobalt_sigwait_context, wc);
+               if (sigismember(swc->set, sig))
+                       goto deliver;
+       }
 
-       wc = xnthread_get_wait_context(&thread->threadbase);
-       swc = container_of(wc, struct cobalt_sigwait_context, wc);
-       if (!sigismember(swc->set, sig))
+       /*
+        * If that does not work out and we are sending to a thread
+        * group, try to deliver to any thread from the same process
+        * waiting for that signal.
+        */
+       if (!group || list_empty(&thread->process->sigwaiters))
                return 0;
 
+       list_for_each_entry(thread, &thread->process->sigwaiters, signext) {
+               wc = xnthread_get_wait_context(&thread->threadbase);
+               swc = container_of(wc, struct cobalt_sigwait_context, wc);
+               if (sigismember(swc->set, sig))
+                       goto deliver;
+       }
+
+       return 0;
+deliver:
        cobalt_copy_siginfo(sigp->si.si_code, swc->si, &sigp->si);
        cobalt_call_extension(signal_deliver, &thread->extref,
                              ret, swc->si, sigp);
        xnsynch_wakeup_one_sleeper(&thread->sigwait);
+       list_del(&thread->signext);
 
        /*
         * This is an immediate delivery bypassing any queuing, so we
@@ -74,13 +96,14 @@ static int cobalt_signal_deliver(struct cobalt_thread 
*thread,
 }
 
 int cobalt_signal_send(struct cobalt_thread *thread,
-                      struct cobalt_sigpending *sigp)
+                      struct cobalt_sigpending *sigp,
+                      int group)
 {                              /* nklocked, IRQs off */
        struct list_head *sigq;
        int sig, ret;
 
        /* Can we deliver this signal immediately? */
-       ret = cobalt_signal_deliver(thread, sigp);
+       ret = cobalt_signal_deliver(thread, sigp, group);
        if (ret)
                return 0;       /* Yep, done. */
 
@@ -119,7 +142,7 @@ int cobalt_signal_send_pid(pid_t pid, struct 
cobalt_sigpending *sigp)
 
        thread = cobalt_thread_find(pid);
        if (thread)
-               return cobalt_signal_send(thread, sigp);
+               return cobalt_signal_send(thread, sigp, 0);
 
        return -ESRCH;
 }
@@ -226,9 +249,11 @@ wait:
        swc.set = set;
        swc.si = &si;
        xnthread_prepare_wait(&swc.wc);
+       list_add_tail(&curr->signext, &curr->process->sigwaiters);
        ret = xnsynch_sleep_on(&curr->sigwait, timeout, XN_RELATIVE);
        xnthread_finish_wait(&swc.wc, NULL);
        if (ret) {
+               list_del(&curr->signext);
                ret = ret & XNBREAK ? -EINTR : -EAGAIN;
                goto fail;
        }
@@ -383,7 +408,7 @@ int cobalt_sigpending(sigset_t __user *u_set)
        return 0;
 }
 
-int __cobalt_kill(struct cobalt_thread *thread, int sig) /* nklocked, IRQs off 
*/
+int __cobalt_kill(struct cobalt_thread *thread, int sig, int group) /* 
nklocked, IRQs off */
 {
        struct cobalt_sigpending *sigp;
        int ret = 0;
@@ -430,7 +455,7 @@ int __cobalt_kill(struct cobalt_thread *thread, int sig) /* 
nklocked, IRQs off *
                        sigp->si.si_code = SI_USER;
                        sigp->si.si_pid = current->pid;
                        sigp->si.si_uid = current_uid();
-                       cobalt_signal_send(thread, sigp);
+                       cobalt_signal_send(thread, sigp, group);
                }
        resched:
                xnsched_run();
@@ -454,7 +479,7 @@ int cobalt_kill(pid_t pid, int sig)
        if (thread == NULL)
                ret = -ESRCH;
        else
-               ret = __cobalt_kill(thread, sig);
+               ret = __cobalt_kill(thread, sig, 1);
 
        xnlock_put_irqrestore(&nklock, s);
 
diff --git a/kernel/cobalt/posix/signal.h b/kernel/cobalt/posix/signal.h
index 59ad42d..26260a4 100644
--- a/kernel/cobalt/posix/signal.h
+++ b/kernel/cobalt/posix/signal.h
@@ -54,7 +54,8 @@ void cobalt_copy_siginfo(int code,
 }
 
 int cobalt_signal_send(struct cobalt_thread *thread,
-                      struct cobalt_sigpending *sigp);
+                      struct cobalt_sigpending *sigp,
+                      int group);
 
 int cobalt_signal_send_pid(pid_t pid,
                           struct cobalt_sigpending *sigp);
@@ -77,7 +78,8 @@ int cobalt_sigwaitinfo(const sigset_t __user *u_set,
 
 int cobalt_sigpending(sigset_t __user *u_set);
 
-int __cobalt_kill(struct cobalt_thread *thread, int sig);
+int __cobalt_kill(struct cobalt_thread *thread,
+                 int sig, int group);
 
 int cobalt_kill(pid_t pid, int sig);
 
diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c
index 7608c9e..81ea80a 100644
--- a/kernel/cobalt/posix/syscall.c
+++ b/kernel/cobalt/posix/syscall.c
@@ -58,6 +58,7 @@ static struct xnshadow_ppd *cobalt_process_attach(void)
        INIT_LIST_HEAD(&cc->kqueues.eventq);
        INIT_LIST_HEAD(&cc->uqds);
        INIT_LIST_HEAD(&cc->usems);
+       INIT_LIST_HEAD(&cc->sigwaiters);
 
        return &cc->ppd;
 }
@@ -177,6 +178,7 @@ struct xnpersonality cobalt_personality = {
        .ops = {
                .attach_process = cobalt_process_attach,
                .detach_process = cobalt_process_detach,
+               .map_thread = cobalt_thread_map,
                .exit_thread = cobalt_thread_exit,
                .finalize_thread = cobalt_thread_finalize,
        },
diff --git a/kernel/cobalt/posix/thread.c b/kernel/cobalt/posix/thread.c
index 55216e1..8516000 100644
--- a/kernel/cobalt/posix/thread.c
+++ b/kernel/cobalt/posix/thread.c
@@ -210,6 +210,18 @@ struct cobalt_thread *cobalt_thread_find_local(pid_t pid) 
/* nklocked, IRQs off
 }
 EXPORT_SYMBOL_GPL(cobalt_thread_find_local);
 
+struct xnpersonality *cobalt_thread_map(struct xnthread *curr)
+{
+       struct cobalt_thread *thread;
+
+       thread = container_of(curr, struct cobalt_thread, threadbase);
+       thread->process = cobalt_process_context();
+       XENO_BUGON(NUCLEUS, thread->process == NULL);
+
+       /* We don't stack over any personality, no chaining. */
+       return NULL;
+}
+
 struct xnpersonality *cobalt_thread_exit(struct xnthread *curr)
 {
        struct cobalt_thread *thread;
@@ -229,7 +241,6 @@ struct xnpersonality *cobalt_thread_exit(struct xnthread 
*curr)
        xnsynch_destroy(&thread->monitor_synch);
        xnsynch_destroy(&thread->sigwait);
 
-       /* We don't stack over any personality, no chaining. */
        return NULL;
 }
 
@@ -916,9 +927,10 @@ fail:
        return ret;
 }
 
-struct cobalt_thread *cobalt_thread_shadow(struct task_struct *p,
-                              struct cobalt_local_hkey *hkey,
-                              unsigned long __user *u_window_offset)
+struct cobalt_thread *
+cobalt_thread_shadow(struct task_struct *p,
+                    struct cobalt_local_hkey *hkey,
+                    unsigned long __user *u_window_offset)
 {
        struct cobalt_thread *thread = NULL;
        pthread_attr_t attr;
@@ -1074,7 +1086,7 @@ int cobalt_thread_kill(unsigned long pth, int sig)
        if (thread == NULL)
                ret = -ESRCH;
        else
-               ret = __cobalt_kill(thread, sig);
+               ret = __cobalt_kill(thread, sig, 0);
 
        xnlock_put_irqrestore(&nklock, s);
 
diff --git a/kernel/cobalt/posix/thread.h b/kernel/cobalt/posix/thread.h
index ef52b3c..512aa60 100644
--- a/kernel/cobalt/posix/thread.h
+++ b/kernel/cobalt/posix/thread.h
@@ -101,6 +101,7 @@ struct cobalt_thread {
        unsigned int magic;
        struct xnthread threadbase;
        struct cobalt_extref extref;
+       struct cobalt_process *process;
 
        /** cobalt_threadq */
        struct list_head link;
@@ -113,6 +114,7 @@ struct cobalt_thread {
        sigset_t sigpending;
        struct list_head sigqueues[_NSIG]; /* cobalt_sigpending */
        struct xnsynch sigwait;
+       struct list_head signext;
 
        /* Cached value for current policy (user side). */
        int sched_u_policy;
@@ -189,6 +191,8 @@ int cobalt_sched_setconfig_np(int cpu,
                              union sched_config __user *u_config,
                              size_t len);
 
+struct xnpersonality *cobalt_thread_map(struct xnthread *curr);
+
 struct xnpersonality *cobalt_thread_exit(struct xnthread *curr);
 
 struct xnpersonality *cobalt_thread_finalize(struct xnthread *zombie);


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

Reply via email to