[Xenomai-git] Philippe Gerum : cobalt/signal: implement thread group sending
Module: xenomai-forge Branch: master Commit: 800302464f0ad3367ba6341b6ce2354fdbbdf350 URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=800302464f0ad3367ba6341b6ce2354fdbbdf350 Author: Philippe Gerum 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 */ struc
[Xenomai-git] Philippe Gerum : cobalt/signal: implement thread group sending
Module: xenomai-forge Branch: next Commit: 800302464f0ad3367ba6341b6ce2354fdbbdf350 URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=800302464f0ad3367ba6341b6ce2354fdbbdf350 Author: Philippe Gerum 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