Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 198783
b: refs/heads/master
c: fd5db42
h: refs/heads/master
i:
  198781: 59e5300
  198779: 3a65c48
  198775: 045a0d1
  198767: 2537f34
  198751: 0c7448f
  198719: 8cded3b
  198655: 505a0da
v: v3
  • Loading branch information
Manfred Spraul authored and Linus Torvalds committed May 27, 2010
1 parent 7bd6461 commit 33c2bbb
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 14 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: 2dcb22b346be7b7b7e630a8970d69cf3f1111ec1
refs/heads/master: fd5db42254518fbf241dc454e918598fbe494fa2
110 changes: 97 additions & 13 deletions trunk/ipc/sem.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,69 @@ static void unlink_queue(struct sem_array *sma, struct sem_queue *q)
sma->complex_count--;
}

/** check_restart(sma, q)
* @sma: semaphore array
* @q: the operation that just completed
*
* update_queue is O(N^2) when it restarts scanning the whole queue of
* waiting operations. Therefore this function checks if the restart is
* really necessary. It is called after a previously waiting operation
* was completed.
*/
static int check_restart(struct sem_array *sma, struct sem_queue *q)
{
struct sem *curr;
struct sem_queue *h;

/* if the operation didn't modify the array, then no restart */
if (q->alter == 0)
return 0;

/* pending complex operations are too difficult to analyse */
if (sma->complex_count)
return 1;

/* we were a sleeping complex operation. Too difficult */
if (q->nsops > 1)
return 1;

curr = sma->sem_base + q->sops[0].sem_num;

/* No-one waits on this queue */
if (list_empty(&curr->sem_pending))
return 0;

/* the new semaphore value */
if (curr->semval) {
/* It is impossible that someone waits for the new value:
* - q is a previously sleeping simple operation that
* altered the array. It must be a decrement, because
* simple increments never sleep.
* - The value is not 0, thus wait-for-zero won't proceed.
* - If there are older (higher priority) decrements
* in the queue, then they have observed the original
* semval value and couldn't proceed. The operation
* decremented to value - thus they won't proceed either.
*/
BUG_ON(q->sops[0].sem_op >= 0);
return 0;
}
/*
* semval is 0. Check if there are wait-for-zero semops.
* They must be the first entries in the per-semaphore simple queue
*/
h = list_first_entry(&curr->sem_pending, struct sem_queue, simple_list);
BUG_ON(h->nsops != 1);
BUG_ON(h->sops[0].sem_num != q->sops[0].sem_num);

/* Yes, there is a wait-for-zero semop. Restart */
if (h->sops[0].sem_op == 0)
return 1;

/* Again - no-one is waiting for the new value. */
return 0;
}


/**
* update_queue(sma, semnum): Look for tasks that can be completed.
Expand Down Expand Up @@ -469,7 +532,7 @@ static void update_queue(struct sem_array *sma, int semnum)
again:
walk = pending_list->next;
while (walk != pending_list) {
int error, alter;
int error, restart;

q = (struct sem_queue *)((char *)walk - offset);
walk = walk->next;
Expand All @@ -494,22 +557,43 @@ static void update_queue(struct sem_array *sma, int semnum)

unlink_queue(sma, q);

/*
* 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 the new semaphore values.
* - if the operation didn't modify the array, then just
* continue.
*/
alter = q->alter;
if (error)
restart = 0;
else
restart = check_restart(sma, q);

wake_up_sem_queue(q, error);
if (alter && !error)
if (restart)
goto again;
}
}

/** do_smart_update(sma, sops, nsops): Optimized update_queue
* @sma: semaphore array
* @sops: operations that were performed
* @nsops: number of operations
*
* do_smart_update() does the required called to update_queue, based on the
* actual changes that were performed on the semaphore array.
*/
static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsops)
{
int i;

if (sma->complex_count || sops == NULL) {
update_queue(sma, -1);
return;
}

for (i = 0; i < nsops; i++) {
if (sops[i].sem_op > 0 ||
(sops[i].sem_op < 0 &&
sma->sem_base[sops[i].sem_num].semval == 0))
update_queue(sma, sops[i].sem_num);
}
}


/* The following counts are associated to each semaphore:
* semncnt number of tasks waiting on semval being nonzero
* semzcnt number of tasks waiting on semval being zero
Expand Down Expand Up @@ -1225,7 +1309,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current));
if (error <= 0) {
if (alter && error == 0)
update_queue(sma, (nsops == 1) ? sops[0].sem_num : -1);
do_smart_update(sma, sops, nsops);

goto out_unlock_free;
}
Expand Down

0 comments on commit 33c2bbb

Please sign in to comment.