diff options
| author | Nick Piggin <npiggin@suse.de> | 2009-12-15 16:47:29 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 07:20:09 -0800 | 
| commit | 9cad200c7686708b326520a45dd680a4147568a6 (patch) | |
| tree | 76a3299679ef23c945e9371f330559d6bc3d0a43 /ipc | |
| parent | bf17bb717759d50a2733a7a8157a7c4a25d93abc (diff) | |
| download | linux-9cad200c7686708b326520a45dd680a4147568a6.tar.bz2 | |
ipc/sem.c: sem use list operations
Replace the handcoded list operations in update_queue() with the standard
list_for_each_entry macros.
list_for_each_entry_safe() must be used, because list entries can
disappear immediately uppon the wakeup event.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Cc: Pierre Peiffer <peifferp@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc')
| -rw-r--r-- | ipc/sem.c | 75 | 
1 files changed, 31 insertions, 44 deletions
| diff --git a/ipc/sem.c b/ipc/sem.c index cb0070ecf5bf..d377b3adfc3d 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -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;  	}  } |