[Xenomai-git] Philippe Gerum : copperplate/threadobj: prevent priority inversion in threadobj_cancel()
Module: xenomai-3 Branch: master Commit: d3a61fef180f14f7de88f319d8e4a8e981013355 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=d3a61fef180f14f7de88f319d8e4a8e981013355 Author: Philippe Gerum 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, + ¤t->schedparam); pthread_cancel(ptid); return 0; ___ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git
[Xenomai-git] Philippe Gerum : copperplate/threadobj: prevent priority inversion in threadobj_cancel()
Module: xenomai-3 Branch: next Commit: d3a61fef180f14f7de88f319d8e4a8e981013355 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=d3a61fef180f14f7de88f319d8e4a8e981013355 Author: Philippe Gerum 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, + ¤t->schedparam); pthread_cancel(ptid); return 0; ___ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git
[Xenomai-git] Philippe Gerum : copperplate/threadobj: prevent priority inversion in threadobj_cancel()
Module: xenomai-3 Branch: next Commit: 8431d7149405235fb0aebb53ed32a537ad968c7e URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=8431d7149405235fb0aebb53ed32a537ad968c7e Author: Philippe Gerum 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 | 26 -- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/copperplate/threadobj.c b/lib/copperplate/threadobj.c index 1dcf9bd..395c403 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,7 @@ 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(); pthread_t ptid = thobj->ptid; #ifdef CONFIG_XENO_PSHARED struct remote_request *rq; @@ -1008,7 +1015,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 +1028,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 && thobj->global_priority < current->global_priority) + copperplate_renice_local_thread(ptid, current->policy, + ¤t->schedparam); pthread_cancel(ptid); return 0; ___ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git