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

Author: Philippe Gerum <r...@xenomai.org>
Date:   Fri May  1 18:41:49 2015 +0200

copperplate/threadobj: prevent priority inversion in threadobj_cancel()

We provide a guarantee to threadobj_cancel() callers that the killed
thread has actually exited when the call returns.

This change fixes an issue with L < M < H priority threads, with H
calling threadobj_cancel() on L, while M is spinning. To address this,
we boost L to H's priority before waiting for the "deletion confirmed"
event, which is sent from L's finalizer.

---

 lib/copperplate/threadobj.c |   27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/lib/copperplate/threadobj.c b/lib/copperplate/threadobj.c
index 1dcf9bd..5a528fa 100644
--- a/lib/copperplate/threadobj.c
+++ b/lib/copperplate/threadobj.c
@@ -88,6 +88,8 @@ static pid_t agent_pid;
 
 struct remote_cancel {
        pthread_t ptid;
+       int policy;
+       struct sched_param_ex param_ex;
 };
 
 struct remote_setsched {
@@ -139,6 +141,10 @@ static void *agent_loop(void *arg)
                                                              
&rq->u.setsched.param_ex);
                        break;
                case RMT_CANCEL:
+                       if (rq->u.cancel.policy != -1)
+                               
copperplate_renice_local_thread(rq->u.cancel.ptid,
+                                                               
rq->u.cancel.policy,
+                                                               
&rq->u.cancel.param_ex);
                        ret = pthread_cancel(rq->u.cancel.ptid);
                        break;
                default:
@@ -995,6 +1001,8 @@ static int request_setschedparam(struct threadobj *thobj, 
int policy,
 
 static int request_cancel(struct threadobj *thobj) /* thobj->lock held, 
dropped. */
 {
+       struct threadobj *current = threadobj_current();
+       int thprio = thobj->global_priority;
        pthread_t ptid = thobj->ptid;
 #ifdef CONFIG_XENO_PSHARED
        struct remote_request *rq;
@@ -1008,7 +1016,11 @@ static int request_cancel(struct threadobj *thobj) /* 
thobj->lock held, dropped.
 
                rq->req = RMT_CANCEL;
                rq->u.cancel.ptid = ptid;
-
+               rq->u.cancel.policy = -1;
+               if (current) {
+                       rq->u.cancel.policy = current->policy;
+                       rq->u.cancel.param_ex = current->schedparam;
+               }
                ret = __bt(send_agent(thobj, rq));
                if (ret)
                        xnfree(rq);
@@ -1017,8 +1029,19 @@ static int request_cancel(struct threadobj *thobj) /* 
thobj->lock held, dropped.
 #endif
        threadobj_unlock(thobj);
 
-       /* We might race, glibc will check. */
+       /*
+        * The caller will have to wait for the killed thread to enter
+        * its finalizer, so we boost the latter thread to prevent a
+        * priority inversion if need be.
+        *
+        * NOTE: Since we dropped the lock, we might race if ptid
+        * disappears while we are busy killing it, glibc will check
+        * and dismiss if so.
+        */
 
+       if (current && thprio < current->global_priority)
+               copperplate_renice_local_thread(ptid, current->policy,
+                                               &current->schedparam);
        pthread_cancel(ptid);
 
        return 0;


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

Reply via email to