Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 176691
b: refs/heads/master
c: 9cad200
h: refs/heads/master
i:
  176689: 24187a7
  176687: 9f81aa3
v: v3
  • Loading branch information
Nick Piggin authored and Linus Torvalds committed Dec 16, 2009
1 parent 53d1ac8 commit 032370e
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 45 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: bf17bb717759d50a2733a7a8157a7c4a25d93abc
refs/heads/master: 9cad200c7686708b326520a45dd680a4147568a6
75 changes: 31 additions & 44 deletions trunk/ipc/sem.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,58 +403,45 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
*/
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;
}
}

Expand Down

0 comments on commit 032370e

Please sign in to comment.