Module: xenomai-forge Branch: next Commit: 8fdde512c53aa410e5e2770a90cc8de4f9213dae URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=8fdde512c53aa410e5e2770a90cc8de4f9213dae
Author: Philippe Gerum <r...@xenomai.org> Date: Wed Jun 5 19:41:30 2013 +0200 psos/tm: fix race in timer removal code The initial code would race in delete_timer() against the task finalizer by lack of synchronization on the task lock. In addition, as observed in a SMP situation, such lack of locking results in no memory barrier being issued after removing the timer from the per-task timer_list queue, which eventually causes a remote CPU altering this queue concurrently to work on stale pointers. --- lib/psos/task.c | 35 ++++++++++++++++++++--------------- lib/psos/task.h | 2 ++ lib/psos/tm.c | 27 ++++++++++++++++++++------- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/lib/psos/task.c b/lib/psos/task.c index 3218cba..51feff6 100644 --- a/lib/psos/task.c +++ b/lib/psos/task.c @@ -643,24 +643,14 @@ out: return ret; } -u_long ev_send(u_long tid, u_long events) +int __ev_send(struct psos_task *task, u_long events) { - struct psos_task *task; struct syncstate syns; - struct service svc; - int ret = SUCCESS; - - task = find_psos_task(tid, &ret); - if (task == NULL) - return ret; - - COPPERPLATE_PROTECT(svc); + int ret; ret = syncobj_lock(&task->sobj, &syns); - if (ret) { - ret = ERR_OBJDEL; - goto out; - } + if (ret) + return ERR_OBJDEL; task->events |= events; /* @@ -672,7 +662,22 @@ u_long ev_send(u_long tid, u_long events) syncobj_grant_one(&task->sobj); syncobj_unlock(&task->sobj, &syns); -out: + + return 0; +} + +u_long ev_send(u_long tid, u_long events) +{ + struct psos_task *task; + struct service svc; + int ret = SUCCESS; + + task = find_psos_task(tid, &ret); + if (task == NULL) + return ret; + + COPPERPLATE_PROTECT(svc); + ret = __ev_send(task, events); COPPERPLATE_UNPROTECT(svc); return ret; diff --git a/lib/psos/task.h b/lib/psos/task.h index 1476f36..a62028a 100644 --- a/lib/psos/task.h +++ b/lib/psos/task.h @@ -69,6 +69,8 @@ struct psos_task *get_psos_task_or_self(u_long tid, int *err_r); void put_psos_task(struct psos_task *task); +int __ev_send(struct psos_task *task, unsigned long events); + extern struct cluster psos_task_table; #endif /* _PSOS_TASK_H */ diff --git a/lib/psos/tm.c b/lib/psos/tm.c index febcd10..7c58631 100644 --- a/lib/psos/tm.c +++ b/lib/psos/tm.c @@ -60,11 +60,24 @@ objid_error: return NULL; } -static void delete_timer(struct psos_tm *tm) +static void delete_timer(struct psos_tm *tm, int signal_p) { + struct psos_task *task; + int ret; + tm->magic = ~tm_magic; /* Prevent further reference. */ timerobj_destroy(&tm->tmobj); - pvlist_remove(&tm->link); + task = get_psos_task(tm->tid, &ret); + if (task) { + pvlist_remove(&tm->link); + /* + * Send out the pending event set carried by the + * deleted timer to the owner thread if requested. + */ + if (signal_p) + __ev_send(task, tm->events); + put_psos_task(task); + } pvfree(tm); } @@ -75,11 +88,11 @@ static void post_event_once(struct timerobj *tmobj) int ret; COPPERPLATE_PROTECT(svc); + ret = timerobj_lock(&tm->tmobj); - if (ret == 0) { - ev_send(tm->tid, tm->events); - delete_timer(tm); - } + if (ret == 0) + delete_timer(tm, 1); + COPPERPLATE_UNPROTECT(svc); } @@ -253,7 +266,7 @@ u_long tm_cancel(u_long tmid) tm = get_tm(tmid, &ret); if (tm) - delete_timer(tm); + delete_timer(tm, 0); COPPERPLATE_UNPROTECT(svc); _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git