rcuja fix: del wrt concurrency
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 23 May 2013 15:16:13 +0000 (11:16 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 23 May 2013 15:16:13 +0000 (11:16 -0400)
testing with:
test_urcu_ja 0 3 10 -v -M 1 -N 1 -O 1

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
rcuja/rcuja.c

index e6e3a3e6bcc5a10dcc6f0f24354ac5d2788c0573..d849537bba0002a7d0fb3362096b0378631e7a99 100644 (file)
@@ -1336,29 +1336,35 @@ static
 int ja_unchain_node(struct cds_ja *ja,
                struct cds_ja_inode_flag *parent_node_flag,
                struct cds_ja_inode_flag **node_flag_ptr,
-               struct cds_hlist_head *head,
+               struct cds_ja_inode_flag *node_flag,
                struct cds_ja_node *node)
 {
        struct cds_ja_shadow_node *shadow_node;
        struct cds_hlist_node *hlist_node;
-       int ret = 0, count = 0;
+       struct cds_hlist_head hlist_head;
+       int ret = 0, count = 0, found = 0;
 
        shadow_node = rcuja_shadow_lookup_lock(ja->ht, parent_node_flag);
        if (!shadow_node)
                return -EAGAIN;
-       if (!ja_node_ptr(*node_flag_ptr)) {
+       if (ja_node_ptr(*node_flag_ptr) != ja_node_ptr(node_flag)) {
                ret = -EAGAIN;
                goto end;
        }
+       hlist_head.next = (struct cds_hlist_node *) ja_node_ptr(node_flag);
        /*
         * Retry if another thread removed all but one of duplicates
         * since check (this check was performed without lock).
+        * Ensure that the node we are about to remove is still in the
+        * list (while holding lock).
         */
-       cds_hlist_for_each_rcu(hlist_node, head, list) {
+       cds_hlist_for_each_rcu(hlist_node, &hlist_head) {
                count++;
+               if (hlist_node == &node->list)
+                       found++;
        }
-
-       if (count == 1) {
+       assert(found <= 1);
+       if (!found || count == 1) {
                ret = -EAGAIN;
                goto end;
        }
@@ -1465,7 +1471,7 @@ retry:
                                        snapshot_n, nr_snapshot, key, node);
                } else {
                        ret = ja_unchain_node(ja, snapshot[nr_snapshot - 1],
-                               node_flag_ptr, &hlist_head, match);
+                               node_flag_ptr, node_flag, match);
                }
        }
        /*
This page took 0.026459 seconds and 4 git commands to generate.