rcuja: API change: move rcu_head to user code
[userspace-rcu.git] / rcuja / rcuja.c
index e6c6d5b51493e8b5bbc58d3044c04ae2a84bb183..4d1f2b435a1433c44cdc3a8ae0983178000e0160 100644 (file)
@@ -1738,10 +1738,6 @@ struct cds_hlist_head cds_ja_lookup(struct cds_ja *ja, uint64_t key)
        return head;
 }
 
-/*
- * cds_ja_lookup_lower_equal() may need to retry if a concurrent removal
- * causes failure to find the previous node.
- */
 struct cds_hlist_head cds_ja_lookup_lower_equal(struct cds_ja *ja, uint64_t key)
 {
        int tree_depth, level;
@@ -1751,7 +1747,6 @@ struct cds_hlist_head cds_ja_lookup_lower_equal(struct cds_ja *ja, uint64_t key)
        if (caa_unlikely(key > ja->key_max || !key))
                return head;
 
-retry:
        memset(cur_node_depth, 0, sizeof(cur_node_depth));
        tree_depth = ja->tree_depth;
        node_flag = rcu_dereference(ja->root);
@@ -1806,14 +1801,10 @@ retry:
        level++;
 
        /*
-        * From this point, we should be able to find a "lower than"
-        * match. The only reason why we could fail to find such a match
-        * would be due to a concurrent removal of the branch that
-        * contains the match. If this happens, we have no choice but to
-        * retry the entire lookup. Indeed, just because we reached a
-        * dead-end due to concurrent removal of the branch does not
-        * mean that other match don't exist. However, this requires
-        * going up into the tree, hence the retry.
+        * From this point, we are guaranteed to be able to find a
+        * "lower than" match. ja_attach_node() and ja_detach_node()
+        * both guarantee that it is not possible for a lookup to reach
+        * a dead-end.
         */
 
        /* Find rightmost child of rightmost child (recursively). */
@@ -1824,15 +1815,8 @@ retry:
                        break;
        }
 
-       if (level != tree_depth) {
-               /*
-                * We did not get a match. Caused by concurrent removal.
-                * We need to retry the entire lookup.
-                */
-               goto retry;
-       }
+       assert(level == tree_depth);
 
-       /* Last level lookup succeded. We got a "lower than" match. */
        head.next = (struct cds_hlist_node *) node_flag;
        return head;
 }
@@ -1848,6 +1832,12 @@ retry:
  * parent lock (if needed).  Then we can proceed to create the new
  * branch. Publish the new branch, and release locks.
  * TODO: we currently always take the parent lock even when not needed.
+ *
+ * ja_attach_node() ensures that a lookup will _never_ see a branch that
+ * leads to a dead-end: before attaching a branch, the entire content of
+ * the new branch is populated, thus creating a cluster, before
+ * attaching the cluster to the rest of the tree, thus making it visible
+ * to lookups.
  */
 static
 int ja_attach_node(struct cds_ja *ja,
@@ -2163,6 +2153,11 @@ struct cds_ja_node *cds_ja_add_unique(struct cds_ja *ja, uint64_t key,
  * However, when a child is removed from "linear" nodes, its pointer
  * is set to NULL. We therefore check, while holding the locks, if this
  * pointer is NULL, and return -ENOENT to the caller if it is the case.
+ *
+ * ja_detach_node() ensures that a lookup will _never_ see a branch that
+ * leads to a dead-end: when removing branch, it makes sure to perform
+ * the "cut" at the highest node that has only one child, effectively
+ * replacing it with a NULL pointer.
  */
 static
 int ja_detach_node(struct cds_ja *ja,
@@ -2534,14 +2529,12 @@ ja_error:
 __attribute__((visibility("protected")))
 void rcuja_free_all_children(struct cds_ja_shadow_node *shadow_node,
                struct cds_ja_inode_flag *node_flag,
-               void (*free_node_cb)(struct rcu_head *head))
+               void (*rcu_free_node)(struct cds_ja_node *node))
 {
-       const struct rcu_flavor_struct *flavor;
        unsigned int type_index;
        struct cds_ja_inode *node;
        const struct cds_ja_type *type;
 
-       flavor = cds_lfht_rcu_flavor(shadow_node->ja->ht);
        node = ja_node_ptr(node_flag);
        assert(node != NULL);
        type_index = ja_node_type(node_flag);
@@ -2566,7 +2559,7 @@ void rcuja_free_all_children(struct cds_ja_shadow_node *shadow_node,
                                continue;
                        head.next = (struct cds_hlist_node *) iter;
                        cds_hlist_for_each_entry_safe(entry, pos, tmp, &head, list) {
-                               flavor->update_call_rcu(&entry->head, free_node_cb);
+                               rcu_free_node(entry);
                        }
                }
                break;
@@ -2594,7 +2587,7 @@ void rcuja_free_all_children(struct cds_ja_shadow_node *shadow_node,
                                        continue;
                                head.next = (struct cds_hlist_node *) iter;
                                cds_hlist_for_each_entry_safe(entry, pos, tmp, &head, list) {
-                                       flavor->update_call_rcu(&entry->head, free_node_cb);
+                                       rcu_free_node(entry);
                                }
                        }
                }
@@ -2617,7 +2610,7 @@ void rcuja_free_all_children(struct cds_ja_shadow_node *shadow_node,
                                continue;
                        head.next = (struct cds_hlist_node *) iter;
                        cds_hlist_for_each_entry_safe(entry, pos, tmp, &head, list) {
-                               flavor->update_call_rcu(&entry->head, free_node_cb);
+                               rcu_free_node(entry);
                        }
                }
                break;
@@ -2676,7 +2669,7 @@ int ja_final_checks(struct cds_ja *ja)
  * being destroyed (ensured by the caller).
  */
 int cds_ja_destroy(struct cds_ja *ja,
-               void (*free_node_cb)(struct rcu_head *head))
+               void (*rcu_free_node)(struct cds_ja_node *node))
 {
        const struct rcu_flavor_struct *flavor;
        int ret;
@@ -2684,7 +2677,7 @@ int cds_ja_destroy(struct cds_ja *ja,
        flavor = cds_lfht_rcu_flavor(ja->ht);
        rcuja_shadow_prune(ja->ht,
                RCUJA_SHADOW_CLEAR_FREE_NODE | RCUJA_SHADOW_CLEAR_FREE_LOCK,
-               free_node_cb);
+               rcu_free_node);
        flavor->thread_offline();
        ret = rcuja_delete_ht(ja->ht);
        if (ret)
This page took 0.026135 seconds and 4 git commands to generate.