Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 338800
b: refs/heads/master
c: 62da192
h: refs/heads/master
v: v3
  • Loading branch information
Paul E. McKenney committed Oct 20, 2012
1 parent d0cde28 commit 03a935f
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 298 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: d484a215139cf556cb718a7ec7042260b7fc2d28
refs/heads/master: 62da1921292ef789c23a7bf01d671d7572baf377
2 changes: 1 addition & 1 deletion trunk/Documentation/RCU/RTFP.txt
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ Bibtex Entries

@article{Kung80
,author="H. T. Kung and Q. Lehman"
,title="Concurrent Manipulation of Binary Search Trees"
,title="Concurrent Maintenance of Binary Search Trees"
,Year="1980"
,Month="September"
,journal="ACM Transactions on Database Systems"
Expand Down
2 changes: 1 addition & 1 deletion trunk/Documentation/RCU/listRCU.txt
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ RCU ("read-copy update") its name. The RCU code is as follows:
audit_copy_rule(&ne->rule, &e->rule);
ne->rule.action = newaction;
ne->rule.file_count = newfield_count;
list_replace_rcu(&e->list, &ne->list);
list_replace_rcu(e, ne);
call_rcu(&e->rcu, audit_free_rule);
return 0;
}
Expand Down
61 changes: 2 additions & 59 deletions trunk/Documentation/RCU/rcuref.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ release_referenced() delete()
{ {
... write_lock(&list_lock);
atomic_dec(&el->rc, relfunc) ...
... remove_element
... delete_element
} write_unlock(&list_lock);
...
if (atomic_dec_and_test(&el->rc))
Expand Down Expand Up @@ -52,7 +52,7 @@ release_referenced() delete()
{ {
... spin_lock(&list_lock);
if (atomic_dec_and_test(&el->rc)) ...
call_rcu(&el->head, el_free); remove_element
call_rcu(&el->head, el_free); delete_element
... spin_unlock(&list_lock);
} ...
if (atomic_dec_and_test(&el->rc))
Expand All @@ -64,60 +64,3 @@ Sometimes, a reference to the element needs to be obtained in the
update (write) stream. In such cases, atomic_inc_not_zero() might be
overkill, since we hold the update-side spinlock. One might instead
use atomic_inc() in such cases.

It is not always convenient to deal with "FAIL" in the
search_and_reference() code path. In such cases, the
atomic_dec_and_test() may be moved from delete() to el_free()
as follows:

1. 2.
add() search_and_reference()
{ {
alloc_object rcu_read_lock();
... search_for_element
atomic_set(&el->rc, 1); atomic_inc(&el->rc);
spin_lock(&list_lock); ...

add_element rcu_read_unlock();
... }
spin_unlock(&list_lock); 4.
} delete()
3. {
release_referenced() spin_lock(&list_lock);
{ ...
... remove_element
if (atomic_dec_and_test(&el->rc)) spin_unlock(&list_lock);
kfree(el); ...
... call_rcu(&el->head, el_free);
} ...
5. }
void el_free(struct rcu_head *rhp)
{
release_referenced();
}

The key point is that the initial reference added by add() is not removed
until after a grace period has elapsed following removal. This means that
search_and_reference() cannot find this element, which means that the value
of el->rc cannot increase. Thus, once it reaches zero, there are no
readers that can or ever will be able to reference the element. The
element can therefore safely be freed. This in turn guarantees that if
any reader finds the element, that reader may safely acquire a reference
without checking the value of the reference counter.

In cases where delete() can sleep, synchronize_rcu() can be called from
delete(), so that el_free() can be subsumed into delete as follows:

4.
delete()
{
spin_lock(&list_lock);
...
remove_element
spin_unlock(&list_lock);
...
synchronize_rcu();
if (atomic_dec_and_test(&el->rc))
kfree(el);
...
}
Loading

0 comments on commit 03a935f

Please sign in to comment.