X-Git-Url: https://git.liburcu.org/?a=blobdiff_plain;f=urcu-ht.c;h=324ebed93420dd7957ffd03963aae07340e5001a;hb=567d755011a9f52f13c53d27842150fd9564da7a;hp=0bbdb5d4e8284d28e8de006cb0ea5476eb9dc7f4;hpb=0eb566f42f9694c397afd96a469e1d89af8a4ff5;p=urcu.git diff --git a/urcu-ht.c b/urcu-ht.c index 0bbdb5d..324ebed 100644 --- a/urcu-ht.c +++ b/urcu-ht.c @@ -134,10 +134,12 @@ restart: /* * Restart until we successfully remove the entry, or no entry is left * ((void *)(unsigned long)-ENOENT). + * Deal with concurrent stealers by verifying that there are no element + * in the list still pointing to the element stolen. (del_node) */ void *ht_steal(struct rcu_ht *ht, void *key) { - struct rcu_ht_node **prev, *node; + struct rcu_ht_node **prev, *node, *del_node = NULL; unsigned long hash; void *data; @@ -150,8 +152,12 @@ retry: node = rcu_dereference(*prev); for (;;) { if (likely(!node)) { - data = (void *)(unsigned long)-ENOENT; - goto error; + if (del_node) { + goto end; + } else { + data = (void *)(unsigned long)-ENOENT; + goto error; + } } if (node->key == key) { break; @@ -161,13 +167,18 @@ retry: } /* Found it ! pointer to object is in "prev" */ if (rcu_cmpxchg_pointer(prev, node, node->next) != node) - goto restart; + del_node = node; + goto restart; - /* From that point, we own node. We can free it outside of read lock */ +end: + /* + * From that point, we own node. Note that there can still be concurrent + * RCU readers using it. We can free it outside of read lock after a GP. + */ rcu_read_unlock(); - data = node->data; - call_rcu(free, node); + data = del_node->data; + call_rcu(free, del_node); return data; error: