Hi Mike,
On 09/10/2013 08:30 AM, Mike Galbraith wrote:
You can kill this particular (osim induced) livelock by using Manfred's
completion wakeup scheme. It may not make it all better, but it does
eliminate this trigger, despite that not being what the patch is about.
[snip]
+#elif defined(SYSVSEM_CUSTOM)
+ struct queue_done {
+ atomic_t done;
+ };
+
+ static void queuewakeup_prepare(void)
+ {
+ preempt_disable();
+ }
+
+ static void queuewakeup_completed(void)
+ {
+ preempt_enable();
+ }
+
+ static void queuewakeup_handsoff(struct queue_done *qd)
+ {
+ BUG_ON(atomic_read(&qd->done) != 2);
+ smp_mb();
+ atomic_set(&qd->done, 1);
+ }
+
+ static void queuewakeup_init(struct queue_done *qd)
+ {
+ atomic_set(&qd->done, 2);
+ }
+
+ static void queuewakeup_wait(struct queue_done *qd)
+ {
+ while (atomic_read(&qd->done) != 1)
+ cpu_relax();
+
+ smp_mb();
+ }
Two remarks:
- The reason why a standard waitqueue is not used should be mentioned in
the commit comment:
A standard wait queue that waits with a timeout (or with
TASK_INTERRUPTIBLE) doesn't allow the caller of add_wait_queue to figure
out if the thread was woken up to due expiry of the timer or due to an
explicit wake_up() call.
a) The ipc code must know that in order to decide if the task must
return with -EAGAIN/-EINTR or with 0. Therefore ipc/sem.c, ipc/msg.c and
ipc/mqueue.c use custom queues.
b) These custom queues have a lockless fast-path for a successful
operation - and this fast path must handle the various races that may
happen the timer expires in parallel with a wake_up() call.
- the ipc/msg.c and ipc/mqueue.c should be converted as well (just
search for cpu_relax()).
--
Manfred
--
To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html