cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rbtree_augmented.h (9562B)


      1/* SPDX-License-Identifier: GPL-2.0-or-later */
      2/*
      3  Red Black Trees
      4  (C) 1999  Andrea Arcangeli <andrea@suse.de>
      5  (C) 2002  David Woodhouse <dwmw2@infradead.org>
      6  (C) 2012  Michel Lespinasse <walken@google.com>
      7
      8
      9  tools/linux/include/linux/rbtree_augmented.h
     10
     11  Copied from:
     12  linux/include/linux/rbtree_augmented.h
     13*/
     14
     15#ifndef _TOOLS_LINUX_RBTREE_AUGMENTED_H
     16#define _TOOLS_LINUX_RBTREE_AUGMENTED_H
     17
     18#include <linux/compiler.h>
     19#include <linux/rbtree.h>
     20
     21/*
     22 * Please note - only struct rb_augment_callbacks and the prototypes for
     23 * rb_insert_augmented() and rb_erase_augmented() are intended to be public.
     24 * The rest are implementation details you are not expected to depend on.
     25 *
     26 * See Documentation/core-api/rbtree.rst for documentation and samples.
     27 */
     28
     29struct rb_augment_callbacks {
     30	void (*propagate)(struct rb_node *node, struct rb_node *stop);
     31	void (*copy)(struct rb_node *old, struct rb_node *new);
     32	void (*rotate)(struct rb_node *old, struct rb_node *new);
     33};
     34
     35extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
     36	void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
     37
     38/*
     39 * Fixup the rbtree and update the augmented information when rebalancing.
     40 *
     41 * On insertion, the user must update the augmented information on the path
     42 * leading to the inserted node, then call rb_link_node() as usual and
     43 * rb_insert_augmented() instead of the usual rb_insert_color() call.
     44 * If rb_insert_augmented() rebalances the rbtree, it will callback into
     45 * a user provided function to update the augmented information on the
     46 * affected subtrees.
     47 */
     48static inline void
     49rb_insert_augmented(struct rb_node *node, struct rb_root *root,
     50		    const struct rb_augment_callbacks *augment)
     51{
     52	__rb_insert_augmented(node, root, augment->rotate);
     53}
     54
     55static inline void
     56rb_insert_augmented_cached(struct rb_node *node,
     57			   struct rb_root_cached *root, bool newleft,
     58			   const struct rb_augment_callbacks *augment)
     59{
     60	if (newleft)
     61		root->rb_leftmost = node;
     62	rb_insert_augmented(node, &root->rb_root, augment);
     63}
     64
     65/*
     66 * Template for declaring augmented rbtree callbacks (generic case)
     67 *
     68 * RBSTATIC:    'static' or empty
     69 * RBNAME:      name of the rb_augment_callbacks structure
     70 * RBSTRUCT:    struct type of the tree nodes
     71 * RBFIELD:     name of struct rb_node field within RBSTRUCT
     72 * RBAUGMENTED: name of field within RBSTRUCT holding data for subtree
     73 * RBCOMPUTE:   name of function that recomputes the RBAUGMENTED data
     74 */
     75
     76#define RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME,				\
     77			     RBSTRUCT, RBFIELD, RBAUGMENTED, RBCOMPUTE)	\
     78static inline void							\
     79RBNAME ## _propagate(struct rb_node *rb, struct rb_node *stop)		\
     80{									\
     81	while (rb != stop) {						\
     82		RBSTRUCT *node = rb_entry(rb, RBSTRUCT, RBFIELD);	\
     83		if (RBCOMPUTE(node, true))				\
     84			break;						\
     85		rb = rb_parent(&node->RBFIELD);				\
     86	}								\
     87}									\
     88static inline void							\
     89RBNAME ## _copy(struct rb_node *rb_old, struct rb_node *rb_new)		\
     90{									\
     91	RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD);		\
     92	RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD);		\
     93	new->RBAUGMENTED = old->RBAUGMENTED;				\
     94}									\
     95static void								\
     96RBNAME ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new)	\
     97{									\
     98	RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD);		\
     99	RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD);		\
    100	new->RBAUGMENTED = old->RBAUGMENTED;				\
    101	RBCOMPUTE(old, false);						\
    102}									\
    103RBSTATIC const struct rb_augment_callbacks RBNAME = {			\
    104	.propagate = RBNAME ## _propagate,				\
    105	.copy = RBNAME ## _copy,					\
    106	.rotate = RBNAME ## _rotate					\
    107};
    108
    109/*
    110 * Template for declaring augmented rbtree callbacks,
    111 * computing RBAUGMENTED scalar as max(RBCOMPUTE(node)) for all subtree nodes.
    112 *
    113 * RBSTATIC:    'static' or empty
    114 * RBNAME:      name of the rb_augment_callbacks structure
    115 * RBSTRUCT:    struct type of the tree nodes
    116 * RBFIELD:     name of struct rb_node field within RBSTRUCT
    117 * RBTYPE:      type of the RBAUGMENTED field
    118 * RBAUGMENTED: name of RBTYPE field within RBSTRUCT holding data for subtree
    119 * RBCOMPUTE:   name of function that returns the per-node RBTYPE scalar
    120 */
    121
    122#define RB_DECLARE_CALLBACKS_MAX(RBSTATIC, RBNAME, RBSTRUCT, RBFIELD,	      \
    123				 RBTYPE, RBAUGMENTED, RBCOMPUTE)	      \
    124static inline bool RBNAME ## _compute_max(RBSTRUCT *node, bool exit)	      \
    125{									      \
    126	RBSTRUCT *child;						      \
    127	RBTYPE max = RBCOMPUTE(node);					      \
    128	if (node->RBFIELD.rb_left) {					      \
    129		child = rb_entry(node->RBFIELD.rb_left, RBSTRUCT, RBFIELD);   \
    130		if (child->RBAUGMENTED > max)				      \
    131			max = child->RBAUGMENTED;			      \
    132	}								      \
    133	if (node->RBFIELD.rb_right) {					      \
    134		child = rb_entry(node->RBFIELD.rb_right, RBSTRUCT, RBFIELD);  \
    135		if (child->RBAUGMENTED > max)				      \
    136			max = child->RBAUGMENTED;			      \
    137	}								      \
    138	if (exit && node->RBAUGMENTED == max)				      \
    139		return true;						      \
    140	node->RBAUGMENTED = max;					      \
    141	return false;							      \
    142}									      \
    143RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME,					      \
    144		     RBSTRUCT, RBFIELD, RBAUGMENTED, RBNAME ## _compute_max)
    145
    146
    147#define	RB_RED		0
    148#define	RB_BLACK	1
    149
    150#define __rb_parent(pc)    ((struct rb_node *)(pc & ~3))
    151
    152#define __rb_color(pc)     ((pc) & 1)
    153#define __rb_is_black(pc)  __rb_color(pc)
    154#define __rb_is_red(pc)    (!__rb_color(pc))
    155#define rb_color(rb)       __rb_color((rb)->__rb_parent_color)
    156#define rb_is_red(rb)      __rb_is_red((rb)->__rb_parent_color)
    157#define rb_is_black(rb)    __rb_is_black((rb)->__rb_parent_color)
    158
    159static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
    160{
    161	rb->__rb_parent_color = rb_color(rb) | (unsigned long)p;
    162}
    163
    164static inline void rb_set_parent_color(struct rb_node *rb,
    165				       struct rb_node *p, int color)
    166{
    167	rb->__rb_parent_color = (unsigned long)p | color;
    168}
    169
    170static inline void
    171__rb_change_child(struct rb_node *old, struct rb_node *new,
    172		  struct rb_node *parent, struct rb_root *root)
    173{
    174	if (parent) {
    175		if (parent->rb_left == old)
    176			WRITE_ONCE(parent->rb_left, new);
    177		else
    178			WRITE_ONCE(parent->rb_right, new);
    179	} else
    180		WRITE_ONCE(root->rb_node, new);
    181}
    182
    183extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
    184	void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
    185
    186static __always_inline struct rb_node *
    187__rb_erase_augmented(struct rb_node *node, struct rb_root *root,
    188		     const struct rb_augment_callbacks *augment)
    189{
    190	struct rb_node *child = node->rb_right;
    191	struct rb_node *tmp = node->rb_left;
    192	struct rb_node *parent, *rebalance;
    193	unsigned long pc;
    194
    195	if (!tmp) {
    196		/*
    197		 * Case 1: node to erase has no more than 1 child (easy!)
    198		 *
    199		 * Note that if there is one child it must be red due to 5)
    200		 * and node must be black due to 4). We adjust colors locally
    201		 * so as to bypass __rb_erase_color() later on.
    202		 */
    203		pc = node->__rb_parent_color;
    204		parent = __rb_parent(pc);
    205		__rb_change_child(node, child, parent, root);
    206		if (child) {
    207			child->__rb_parent_color = pc;
    208			rebalance = NULL;
    209		} else
    210			rebalance = __rb_is_black(pc) ? parent : NULL;
    211		tmp = parent;
    212	} else if (!child) {
    213		/* Still case 1, but this time the child is node->rb_left */
    214		tmp->__rb_parent_color = pc = node->__rb_parent_color;
    215		parent = __rb_parent(pc);
    216		__rb_change_child(node, tmp, parent, root);
    217		rebalance = NULL;
    218		tmp = parent;
    219	} else {
    220		struct rb_node *successor = child, *child2;
    221
    222		tmp = child->rb_left;
    223		if (!tmp) {
    224			/*
    225			 * Case 2: node's successor is its right child
    226			 *
    227			 *    (n)          (s)
    228			 *    / \          / \
    229			 *  (x) (s)  ->  (x) (c)
    230			 *        \
    231			 *        (c)
    232			 */
    233			parent = successor;
    234			child2 = successor->rb_right;
    235
    236			augment->copy(node, successor);
    237		} else {
    238			/*
    239			 * Case 3: node's successor is leftmost under
    240			 * node's right child subtree
    241			 *
    242			 *    (n)          (s)
    243			 *    / \          / \
    244			 *  (x) (y)  ->  (x) (y)
    245			 *      /            /
    246			 *    (p)          (p)
    247			 *    /            /
    248			 *  (s)          (c)
    249			 *    \
    250			 *    (c)
    251			 */
    252			do {
    253				parent = successor;
    254				successor = tmp;
    255				tmp = tmp->rb_left;
    256			} while (tmp);
    257			child2 = successor->rb_right;
    258			WRITE_ONCE(parent->rb_left, child2);
    259			WRITE_ONCE(successor->rb_right, child);
    260			rb_set_parent(child, successor);
    261
    262			augment->copy(node, successor);
    263			augment->propagate(parent, successor);
    264		}
    265
    266		tmp = node->rb_left;
    267		WRITE_ONCE(successor->rb_left, tmp);
    268		rb_set_parent(tmp, successor);
    269
    270		pc = node->__rb_parent_color;
    271		tmp = __rb_parent(pc);
    272		__rb_change_child(node, successor, tmp, root);
    273
    274		if (child2) {
    275			successor->__rb_parent_color = pc;
    276			rb_set_parent_color(child2, parent, RB_BLACK);
    277			rebalance = NULL;
    278		} else {
    279			unsigned long pc2 = successor->__rb_parent_color;
    280			successor->__rb_parent_color = pc;
    281			rebalance = __rb_is_black(pc2) ? parent : NULL;
    282		}
    283		tmp = successor;
    284	}
    285
    286	augment->propagate(tmp, NULL);
    287	return rebalance;
    288}
    289
    290static __always_inline void
    291rb_erase_augmented(struct rb_node *node, struct rb_root *root,
    292		   const struct rb_augment_callbacks *augment)
    293{
    294	struct rb_node *rebalance = __rb_erase_augmented(node, root, augment);
    295	if (rebalance)
    296		__rb_erase_color(rebalance, root, augment->rotate);
    297}
    298
    299static __always_inline void
    300rb_erase_augmented_cached(struct rb_node *node, struct rb_root_cached *root,
    301			  const struct rb_augment_callbacks *augment)
    302{
    303	if (root->rb_leftmost == node)
    304		root->rb_leftmost = rb_next(node);
    305	rb_erase_augmented(node, &root->rb_root, augment);
    306}
    307
    308#endif /* _TOOLS_LINUX_RBTREE_AUGMENTED_H */