| /* Copyright (c) 2010 The Regents of the University of California |
| * Barret Rhoden <brho@cs.berkeley.edu> |
| * See LICENSE for details. |
| * |
| * Radix Tree, modeled after Linux's (described here: |
| * http://lwn.net/Articles/175432/). |
| * |
| * It maps unsigned longs to void*s, growing the depth of the tree as needed to |
| * handle more items. It won't allow the insertion of existing keys, and it |
| * can fail due to lack of memory. |
| * |
| * There are some utility functions, probably unimplemented til we need them, |
| * that will make the tree have enough memory for future calls. |
| * |
| * You can also store a tag along with the void* for a given item, and do |
| * lookups based on those tags. Or you will be able to, once it is |
| * implemented. */ |
| |
| #pragma once |
| |
| #define LOG_RNODE_SLOTS 6 |
| #define NR_RNODE_SLOTS (1 << LOG_RNODE_SLOTS) |
| |
| #include <ros/common.h> |
| #include <kthread.h> |
| #include <atomic.h> |
| #include <rcu.h> |
| |
| struct radix_node { |
| struct rcu_head rcu; |
| void *items[NR_RNODE_SLOTS]; |
| unsigned int num_items; |
| bool leaf; |
| struct radix_node *parent; |
| struct radix_node **my_slot; |
| }; |
| |
| /* writers (insert, delete, and callbacks) must synchronize externally, e.g. a |
| * qlock in the pagemap. |
| * |
| * radix_lookup_slot returns an rcu-protected pointer that needs to be |
| * rcu_read_locked. The item in the slot (either by *slot or by a regular |
| * radix_lookup) has limited protections. Higher layers (pagemap) can do their |
| * own thing. For instance, the page cache writers can zero an item if they |
| * know they cleared the page without someone else grabbing a ref. We'll |
| * rcu-protect the item pointer, so that higher layers can use RCU for the |
| * actual object. |
| * |
| * Basically the only functions that don't need the caller to hold a qlock are |
| * the two lookup routines: the readers. The seq counter protects the atomicity |
| * of root, depth, and upper_bound, which defines the reader's start point. RCU |
| * protects the lifetime of the rnodes, which is where lookup_slot's pointer |
| * points to. |
| * |
| * Note that we use rcu_assign_pointer and rcu_dereference whenever we |
| * manipulate pointers in the tree (pointers to or within rnodes). We use RCU |
| * for the item pointer too, so that our callers can use RCU if they want. Both |
| * the slot pointer and what it points to are protected by RCU. |
| */ |
| struct radix_tree { |
| seq_ctr_t seq; |
| struct radix_node *root; |
| unsigned int depth; |
| unsigned long upper_bound; |
| }; |
| |
| void radix_init(void); /* initializes the whole radix system */ |
| void radix_tree_init(struct radix_tree *tree); /* inits one tree */ |
| void radix_tree_destroy(struct radix_tree *tree); |
| |
| /* Item management */ |
| int radix_insert(struct radix_tree *tree, unsigned long key, void *item, |
| void ***slot_p); |
| void *radix_delete(struct radix_tree *tree, unsigned long key); |
| void *radix_lookup(struct radix_tree *tree, unsigned long key); |
| void **radix_lookup_slot(struct radix_tree *tree, unsigned long key); |
| |
| typedef bool (*radix_cb_t)(void **slot, unsigned long tree_idx, void *arg); |
| void radix_for_each_slot(struct radix_tree *tree, radix_cb_t cb, void *arg); |
| /* [start_idx, end_idx) */ |
| void radix_for_each_slot_in_range(struct radix_tree *tree, |
| unsigned long start_idx, |
| unsigned long end_idx, |
| radix_cb_t cb, void *arg); |
| |
| /* Memory management */ |
| int radix_grow(struct radix_tree *tree, unsigned long max); |
| int radix_preload(struct radix_tree *tree, int flags); |
| |
| /* Tag management */ |
| void *radix_tag_set(struct radix_tree *tree, unsigned long key, int tag); |
| void *radix_tag_clear(struct radix_tree *tree, unsigned long key, int tag); |
| int radix_tag_get(struct radix_tree *tree, unsigned long key, int tag); |
| int radix_tree_tagged(struct radix_tree *tree, int tag); |
| int radix_tag_gang_lookup(struct radix_tree *tree, void **results, |
| unsigned long first, unsigned int max_items, int tag); |
| |
| /* Debugging */ |
| void print_radix_tree(struct radix_tree *tree); |