|
@@ -403,58 +403,45 @@ undo:
|
|
|
*/
|
|
|
static void update_queue (struct sem_array * sma)
|
|
|
{
|
|
|
- int error;
|
|
|
- struct sem_queue * q;
|
|
|
+ struct sem_queue *q, *tq;
|
|
|
+
|
|
|
+again:
|
|
|
+ list_for_each_entry_safe(q, tq, &sma->sem_pending, list) {
|
|
|
+ int error;
|
|
|
+ int alter;
|
|
|
|
|
|
- q = list_entry(sma->sem_pending.next, struct sem_queue, list);
|
|
|
- while (&q->list != &sma->sem_pending) {
|
|
|
error = try_atomic_semop(sma, q->sops, q->nsops,
|
|
|
q->undo, q->pid);
|
|
|
|
|
|
/* Does q->sleeper still need to sleep? */
|
|
|
- if (error <= 0) {
|
|
|
- struct sem_queue *n;
|
|
|
+ if (error > 0)
|
|
|
+ continue;
|
|
|
|
|
|
- /*
|
|
|
- * Continue scanning. The next operation
|
|
|
- * that must be checked depends on the type of the
|
|
|
- * completed operation:
|
|
|
- * - if the operation modified the array, then
|
|
|
- * restart from the head of the queue and
|
|
|
- * check for threads that might be waiting
|
|
|
- * for semaphore values to become 0.
|
|
|
- * - if the operation didn't modify the array,
|
|
|
- * then just continue.
|
|
|
- * The order of list_del() and reading ->next
|
|
|
- * is crucial: In the former case, the list_del()
|
|
|
- * must be done first [because we might be the
|
|
|
- * first entry in ->sem_pending], in the latter
|
|
|
- * case the list_del() must be done last
|
|
|
- * [because the list is invalid after the list_del()]
|
|
|
- */
|
|
|
- if (q->alter) {
|
|
|
- list_del(&q->list);
|
|
|
- n = list_entry(sma->sem_pending.next,
|
|
|
- struct sem_queue, list);
|
|
|
- } else {
|
|
|
- n = list_entry(q->list.next, struct sem_queue,
|
|
|
- list);
|
|
|
- list_del(&q->list);
|
|
|
- }
|
|
|
+ list_del(&q->list);
|
|
|
|
|
|
- /* wake up the waiting thread */
|
|
|
- q->status = IN_WAKEUP;
|
|
|
+ /*
|
|
|
+ * The next operation that must be checked depends on the type
|
|
|
+ * of the completed operation:
|
|
|
+ * - if the operation modified the array, then restart from the
|
|
|
+ * head of the queue and check for threads that might be
|
|
|
+ * waiting for semaphore values to become 0.
|
|
|
+ * - if the operation didn't modify the array, then just
|
|
|
+ * continue.
|
|
|
+ */
|
|
|
+ alter = q->alter;
|
|
|
+
|
|
|
+ /* wake up the waiting thread */
|
|
|
+ q->status = IN_WAKEUP;
|
|
|
|
|
|
- wake_up_process(q->sleeper);
|
|
|
- /* hands-off: q will disappear immediately after
|
|
|
- * writing q->status.
|
|
|
- */
|
|
|
- smp_wmb();
|
|
|
- q->status = error;
|
|
|
- q = n;
|
|
|
- } else {
|
|
|
- q = list_entry(q->list.next, struct sem_queue, list);
|
|
|
- }
|
|
|
+ wake_up_process(q->sleeper);
|
|
|
+ /* hands-off: q will disappear immediately after
|
|
|
+ * writing q->status.
|
|
|
+ */
|
|
|
+ smp_wmb();
|
|
|
+ q->status = error;
|
|
|
+
|
|
|
+ if (alter)
|
|
|
+ goto again;
|
|
|
}
|
|
|
}
|
|
|
|