X-Git-Url: https://git.liburcu.org/?a=blobdiff_plain;f=urcu-ht.c;h=324ebed93420dd7957ffd03963aae07340e5001a;hb=567d755011a9f52f13c53d27842150fd9564da7a;hp=49262076d5c33c0964945dc0170fdaf4ab1d2cc9;hpb=5e28c5328529ace4f43b70139acf7ef9b0329c4a;p=urcu.git diff --git a/urcu-ht.c b/urcu-ht.c index 4926207..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: @@ -269,7 +280,7 @@ uint32_t ht_jhash(void *key, uint32_t length, uint32_t initval) uint32_t ret; void *vkey; - if (length <= sizeof(u32)) + if (length <= sizeof(void *)) vkey = &key; else vkey = key;