diff options
Diffstat (limited to 'debian/patches/0008-librdxtree-add-a-radix-tree-implementation.patch')
-rw-r--r-- | debian/patches/0008-librdxtree-add-a-radix-tree-implementation.patch | 1439 |
1 files changed, 1439 insertions, 0 deletions
diff --git a/debian/patches/0008-librdxtree-add-a-radix-tree-implementation.patch b/debian/patches/0008-librdxtree-add-a-radix-tree-implementation.patch new file mode 100644 index 00000000..3e17f9ff --- /dev/null +++ b/debian/patches/0008-librdxtree-add-a-radix-tree-implementation.patch @@ -0,0 +1,1439 @@ +From 70e7e9a7c30a01caf33b89f599b561900a91ac88 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Mon, 19 May 2014 18:42:30 +0200 +Subject: [PATCH 08/18] librdxtree: add a radix tree implementation + +Radix trees offer search, insert, and delete operations in time linear +in the size of the key. They are also very cache efficient. + +This is an verbatim copy from git://git.sceen.net/rbraun/librbraun.git +as of 45fef4ad. Only macros.h has been slightly amended. This file +defines two macros, which are also defined in cthreads.h. Undefine +the macros first to work around this problem. + +* librdxtree/Makefile: New file. +* librdxtree/rdxtree.c: Likewise. +* librdxtree/rdxtree.h: Likewise. +* librdxtree/rdxtree_i.h: Likewise. +* librdxtree/error.c: Likewise. +* librdxtree/error.h: Likewise. +* librdxtree/macros.h: Likewise. Also, undefine MACRO_{BEGIN,END}. +* Makefile (lib-subdirs): Add librdxtree. +--- + Makefile | 1 + + librdxtree/Makefile | 27 ++ + librdxtree/error.c | 94 ++++++ + librdxtree/error.h | 84 +++++ + librdxtree/macros.h | 70 +++++ + librdxtree/rdxtree.c | 808 +++++++++++++++++++++++++++++++++++++++++++++++++ + librdxtree/rdxtree.h | 195 ++++++++++++ + librdxtree/rdxtree_i.h | 65 ++++ + 8 files changed, 1344 insertions(+) + create mode 100644 librdxtree/Makefile + create mode 100644 librdxtree/error.c + create mode 100644 librdxtree/error.h + create mode 100644 librdxtree/macros.h + create mode 100644 librdxtree/rdxtree.c + create mode 100644 librdxtree/rdxtree.h + create mode 100644 librdxtree/rdxtree_i.h + +diff --git a/Makefile b/Makefile +index 8a0be83..53dac72 100644 +--- a/Makefile ++++ b/Makefile +@@ -48,6 +48,7 @@ other-subdirs = hurd doc config release include + + # XXX + lib-subdirs += librbtree ++lib-subdirs += librdxtree + + # All the subdirectories together + subdirs = $(lib-subdirs) $(prog-subdirs) $(other-subdirs) +diff --git a/librdxtree/Makefile b/librdxtree/Makefile +new file mode 100644 +index 0000000..c9d3c9d +--- /dev/null ++++ b/librdxtree/Makefile +@@ -0,0 +1,27 @@ ++# Copyright (C) 2014 Free Software Foundation, Inc. ++# ++# This file is part of the GNU Hurd. ++# ++# The GNU Hurd is free software; you can redistribute it and/or ++# modify it under the terms of the GNU General Public License as ++# published by the Free Software Foundation; either version 2, or (at ++# your option) any later version. ++# ++# The GNU Hurd is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. ++ ++dir := librdxtree ++makemode := library ++ ++libname := librdxtree ++SRCS = rdxtree.c ++installhdrs = rdxtree.h rdxtree_i.h macros.h ++ ++OBJS = $(SRCS:.c=.o) ++ ++include ../Makeconf +diff --git a/librdxtree/error.c b/librdxtree/error.c +new file mode 100644 +index 0000000..dcc574f +--- /dev/null ++++ b/librdxtree/error.c +@@ -0,0 +1,94 @@ ++/* ++ * Copyright (c) 2009, 2010 Richard Braun. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include <errno.h> ++#include <stdio.h> ++#include <stdlib.h> ++ ++#include "error.h" ++#include "macros.h" ++ ++/* ++ * Error message table. ++ * ++ * This table must be consistent with the enum defined in error.h. ++ */ ++static const char *errormsg_table[] = { ++ "success", ++ "unknown error", ++ "invalid argument", ++ "not enough space", ++ "invalid format", ++ "not enough resources", ++ "operation not permitted", ++ "resource busy", ++ "memory limit exceeded", ++ "operation timed out", ++ "operation would block", ++ "entry not found", ++ "internal memory allocator failure" ++}; ++ ++#define ERRORMSG_TABLE_SIZE ARRAY_SIZE(errormsg_table) ++ ++const char * ++error_str(unsigned int error) ++{ ++ if (error >= ERRORMSG_TABLE_SIZE) ++ return "invalid error code"; ++ ++ return errormsg_table[error]; ++} ++ ++unsigned int ++error_from_errno(int errno_code) ++{ ++ switch (errno_code) { ++ case 0: ++ return ERR_SUCCESS; ++ case EINVAL: ++ return ERR_INVAL; ++ case ENOMEM: ++ return ERR_NOMEM; ++ case EAGAIN: ++ return ERR_NORES; ++ case EPERM: ++ return ERR_PERM; ++ case EBUSY: ++ return ERR_BUSY; ++ case ETIMEDOUT: ++ return ERR_TIMEDOUT; ++ default: ++ fprintf(stderr, "unable to translate errno code (%d)\n", errno_code); ++ return ERR_UNKNOWN; ++ } ++} ++ ++void ++error_die(unsigned int error) ++{ ++ fprintf(stderr, "process terminating, reason: %s\n", error_str(error)); ++ abort(); ++} +diff --git a/librdxtree/error.h b/librdxtree/error.h +new file mode 100644 +index 0000000..81babf7 +--- /dev/null ++++ b/librdxtree/error.h +@@ -0,0 +1,84 @@ ++/* ++ * Copyright (c) 2009, 2010 Richard Braun. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef _ERROR_H ++#define _ERROR_H ++ ++#include "macros.h" ++ ++/* ++ * List of errors this library can return. ++ * ++ * ERR_SUCCESS is guaranteed to be 0, allowing code such as : ++ * ++ * error = do_smth(); ++ * ++ * if (error) { ++ * ...; ++ * } ++ */ ++enum { ++ ERR_SUCCESS, ++ ERR_UNKNOWN, ++ ERR_INVAL, ++ ERR_NOMEM, ++ ERR_FORMAT, ++ ERR_NORES, ++ ERR_PERM, ++ ERR_BUSY, ++ ERR_MEMLIM, ++ ERR_TIMEDOUT, ++ ERR_WOULDBLOCK, ++ ERR_LOOKUP, ++ ERR_MEM_CACHE ++}; ++ ++/* ++ * Return the message matching the given error. ++ * ++ * The returned address points to a statically allocated, read only, ++ * null-terminated string literal. The caller must not attempt to use it ++ * for anything else than error reporting. ++ */ ++const char * error_str(unsigned int error); ++ ++/* ++ * Map standard error codes to error values. ++ * ++ * This function accepts a subset of the standard error codes in errno.h. ++ * When called, and if the errno value is handled, it will return the ++ * corresponding ERR_xxx code. Otherwise ERR_UNKNOWN is returned. ++ */ ++unsigned int error_from_errno(int errno_code); ++ ++/* ++ * Exit the current process, reporting an error. ++ * ++ * This function will report the given error and make the process exit, ++ * using the error code as the exit() parameter. ++ */ ++void __noreturn error_die(unsigned int error); ++ ++#endif /* _ERROR_H */ +diff --git a/librdxtree/macros.h b/librdxtree/macros.h +new file mode 100644 +index 0000000..f0960a3 +--- /dev/null ++++ b/librdxtree/macros.h +@@ -0,0 +1,70 @@ ++/* ++ * Copyright (c) 2009, 2010 Richard Braun. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * Helper macros. ++ */ ++ ++#ifndef _MACROS_H ++#define _MACROS_H ++ ++#include <stddef.h> ++ ++#undef MACRO_BEGIN ++#undef MACRO_END ++#define MACRO_BEGIN ({ ++#define MACRO_END }) ++ ++#define XQUOTE(x) #x ++#define QUOTE(x) XQUOTE(x) ++ ++#define STRLEN(x) (sizeof(x) - 1) ++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) ++ ++#define MIN(a, b) ((a) < (b) ? (a) : (b)) ++#define MAX(a, b) ((a) > (b) ? (a) : (b)) ++ ++#define P2ALIGNED(x, a) (((x) & ((a) - 1)) == 0) ++#define ISP2(x) P2ALIGNED(x, x) ++#define P2ALIGN(x, a) ((x) & -(a)) ++#define P2ROUND(x, a) (-(-(x) & -(a))) ++#define P2END(x, a) (-(~(x) & -(a))) ++ ++#define structof(ptr, type, member) \ ++ ((type *)((char *)(ptr) - offsetof(type, member))) ++ ++#define alignof(x) __alignof__(x) ++ ++#define likely(expr) __builtin_expect(!!(expr), 1) ++#define unlikely(expr) __builtin_expect(!!(expr), 0) ++ ++#define barrier() asm volatile("" : : : "memory") ++ ++#define __noreturn __attribute__((noreturn)) ++#define __aligned(x) __attribute__((aligned(x))) ++ ++#define __format_printf(fmt, args) \ ++ __attribute__((format(printf, fmt, args))) ++ ++#endif /* _MACROS_H */ +diff --git a/librdxtree/rdxtree.c b/librdxtree/rdxtree.c +new file mode 100644 +index 0000000..36fd09f +--- /dev/null ++++ b/librdxtree/rdxtree.c +@@ -0,0 +1,808 @@ ++/* ++ * Copyright (c) 2013 Richard Braun. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++/* ++ * Copyright (c) 2011 Richard Braun. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include <assert.h> ++#include <limits.h> ++#include <stddef.h> ++#include <stdlib.h> ++#include <string.h> ++ ++#include "error.h" ++#include "macros.h" ++#include "rdxtree.h" ++#include "rdxtree_i.h" ++ ++/* ++ * Mask applied on an entry to obtain its address. ++ */ ++#define RDXTREE_ENTRY_ADDR_MASK (~0x3UL) ++ ++/* ++ * Global properties used to shape radix trees. ++ */ ++#define RDXTREE_RADIX 6 ++#define RDXTREE_RADIX_SIZE (1UL << RDXTREE_RADIX) ++#define RDXTREE_RADIX_MASK (RDXTREE_RADIX_SIZE - 1) ++ ++#if RDXTREE_RADIX < 6 ++typedef unsigned long rdxtree_bm_t; ++#define rdxtree_ffs(x) __builtin_ffsl(x) ++#elif RDXTREE_RADIX == 6 /* RDXTREE_RADIX < 6 */ ++typedef unsigned long long rdxtree_bm_t; ++#define rdxtree_ffs(x) __builtin_ffsll(x) ++#else /* RDXTREE_RADIX < 6 */ ++#error "radix too high" ++#endif /* RDXTREE_RADIX < 6 */ ++ ++/* ++ * Allocation bitmap size in bits. ++ */ ++#define RDXTREE_BM_SIZE (sizeof(rdxtree_bm_t) * CHAR_BIT) ++ ++/* ++ * Empty/full allocation bitmap words. ++ */ ++#define RDXTREE_BM_EMPTY ((rdxtree_bm_t)0) ++#define RDXTREE_BM_FULL \ ++ ((~(rdxtree_bm_t)0) >> (RDXTREE_BM_SIZE - RDXTREE_RADIX_SIZE)) ++ ++/* ++ * These macros can be replaced by actual functions in an environment ++ * that provides lockless synchronization such as RCU. ++ */ ++#define llsync_assign_ptr(ptr, value) ((ptr) = (value)) ++#define llsync_read_ptr(ptr) (ptr) ++ ++/* ++ * Radix tree node. ++ * ++ * The height of a tree is the number of nodes to traverse until stored ++ * pointers are reached. A height of 0 means the entries of a node (or the ++ * tree root) directly point to stored pointers. ++ * ++ * The index is valid if and only if the parent isn't NULL. ++ * ++ * Concerning the allocation bitmap, a bit is set when the node it denotes, ++ * or one of its children, can be used to allocate an entry. Conversely, a bit ++ * is clear when the matching node and all of its children have no free entry. ++ * ++ * In order to support safe lockless lookups, in particular during a resize, ++ * each node includes the height of its subtree, which is invariant during ++ * the entire node lifetime. Since the tree height does vary, it can't be ++ * used to determine whether the tree root is a node or a stored pointer. ++ * This implementation assumes that all nodes and stored pointers are at least ++ * 4-byte aligned, and uses the least significant bit of entries to indicate ++ * the pointer type. This bit is set for internal nodes, and clear for stored ++ * pointers so that they can be accessed from slots without conversion. ++ */ ++struct rdxtree_node { ++ struct rdxtree_node *parent; ++ unsigned int index; ++ unsigned int height; ++ unsigned int nr_entries; ++ rdxtree_bm_t alloc_bm; ++ void *entries[RDXTREE_RADIX_SIZE]; ++}; ++ ++#ifdef RDXTREE_ENABLE_NODE_CREATION_FAILURES ++unsigned int rdxtree_fail_node_creation_threshold; ++unsigned int rdxtree_nr_node_creations; ++#endif /* RDXTREE_ENABLE_NODE_CREATION_FAILURES */ ++ ++static inline int ++rdxtree_check_alignment(const void *ptr) ++{ ++ return ((unsigned long)ptr & ~RDXTREE_ENTRY_ADDR_MASK) == 0; ++} ++ ++static inline void * ++rdxtree_entry_addr(void *entry) ++{ ++ return (void *)((unsigned long)entry & RDXTREE_ENTRY_ADDR_MASK); ++} ++ ++static inline int ++rdxtree_entry_is_node(const void *entry) ++{ ++ return ((unsigned long)entry & 1) != 0; ++} ++ ++static inline void * ++rdxtree_node_to_entry(struct rdxtree_node *node) ++{ ++ return (void *)((unsigned long)node | 1); ++} ++ ++static int ++rdxtree_node_create(struct rdxtree_node **nodep, unsigned int height) ++{ ++ struct rdxtree_node *node; ++ ++#ifdef RDXTREE_ENABLE_NODE_CREATION_FAILURES ++ if (rdxtree_fail_node_creation_threshold != 0) { ++ rdxtree_nr_node_creations++; ++ ++ if (rdxtree_nr_node_creations == rdxtree_fail_node_creation_threshold) ++ return ERR_NOMEM; ++ } ++#endif /* RDXTREE_ENABLE_NODE_CREATION_FAILURES */ ++ ++ node = malloc(sizeof(*node)); ++ ++ if (node == NULL) ++ return ERR_NOMEM; ++ ++ assert(rdxtree_check_alignment(node)); ++ node->parent = NULL; ++ node->height = height; ++ node->nr_entries = 0; ++ node->alloc_bm = RDXTREE_BM_FULL; ++ memset(node->entries, 0, sizeof(node->entries)); ++ *nodep = node; ++ return 0; ++} ++ ++static void ++rdxtree_node_schedule_destruction(struct rdxtree_node *node) ++{ ++ /* ++ * This function is intended to use the appropriate interface to defer ++ * destruction until all read-side references are dropped in an ++ * environment that provides lockless synchronization. ++ * ++ * Otherwise, it simply "schedules" destruction immediately. ++ */ ++ free(node); ++} ++ ++static inline void ++rdxtree_node_link(struct rdxtree_node *node, struct rdxtree_node *parent, ++ unsigned int index) ++{ ++ node->parent = parent; ++ node->index = index; ++} ++ ++static inline void ++rdxtree_node_unlink(struct rdxtree_node *node) ++{ ++ assert(node->parent != NULL); ++ node->parent = NULL; ++} ++ ++static inline int ++rdxtree_node_full(struct rdxtree_node *node) ++{ ++ return (node->nr_entries == ARRAY_SIZE(node->entries)); ++} ++ ++static inline int ++rdxtree_node_empty(struct rdxtree_node *node) ++{ ++ return (node->nr_entries == 0); ++} ++ ++static inline void ++rdxtree_node_insert(struct rdxtree_node *node, unsigned int index, ++ void *entry) ++{ ++ assert(index < ARRAY_SIZE(node->entries)); ++ assert(node->entries[index] == NULL); ++ ++ node->nr_entries++; ++ llsync_assign_ptr(node->entries[index], entry); ++} ++ ++static inline void ++rdxtree_node_insert_node(struct rdxtree_node *node, unsigned int index, ++ struct rdxtree_node *child) ++{ ++ rdxtree_node_insert(node, index, rdxtree_node_to_entry(child)); ++} ++ ++static inline void ++rdxtree_node_remove(struct rdxtree_node *node, unsigned int index) ++{ ++ assert(index < ARRAY_SIZE(node->entries)); ++ assert(node->entries[index] != NULL); ++ ++ node->nr_entries--; ++ llsync_assign_ptr(node->entries[index], NULL); ++} ++ ++static inline void * ++rdxtree_node_find(struct rdxtree_node *node, unsigned int index, int get_slot) ++{ ++ void *ptr; ++ ++ while (index < ARRAY_SIZE(node->entries)) { ++ ptr = rdxtree_entry_addr(node->entries[index]); ++ ++ if (ptr != NULL) ++ return get_slot ? (void *)&node->entries[index] : ptr; ++ ++ index++; ++ } ++ ++ return NULL; ++} ++ ++static inline void ++rdxtree_node_bm_set(struct rdxtree_node *node, unsigned int index) ++{ ++ node->alloc_bm |= (rdxtree_bm_t)1 << index; ++} ++ ++static inline void ++rdxtree_node_bm_clear(struct rdxtree_node *node, unsigned int index) ++{ ++ node->alloc_bm &= ~((rdxtree_bm_t)1 << index); ++} ++ ++static inline int ++rdxtree_node_bm_is_set(struct rdxtree_node *node, unsigned int index) ++{ ++ return (node->alloc_bm & ((rdxtree_bm_t)1 << index)); ++} ++ ++static inline int ++rdxtree_node_bm_empty(struct rdxtree_node *node) ++{ ++ return (node->alloc_bm == RDXTREE_BM_EMPTY); ++} ++ ++static inline unsigned int ++rdxtree_node_bm_first(struct rdxtree_node *node) ++{ ++ return rdxtree_ffs(node->alloc_bm) - 1; ++} ++ ++static inline unsigned long long ++rdxtree_max_key(unsigned int height) ++{ ++ size_t shift; ++ ++ shift = RDXTREE_RADIX * height; ++ ++ if (likely(shift < (sizeof(unsigned long long) * CHAR_BIT))) ++ return (1ULL << shift) - 1; ++ else ++ return ~0ULL; ++} ++ ++static void ++rdxtree_shrink(struct rdxtree *tree) ++{ ++ struct rdxtree_node *node; ++ void *entry; ++ ++ while (tree->height > 0) { ++ node = rdxtree_entry_addr(tree->root); ++ ++ if (node->nr_entries != 1) ++ break; ++ ++ entry = node->entries[0]; ++ ++ if (entry == NULL) ++ break; ++ ++ tree->height--; ++ ++ if (tree->height > 0) ++ rdxtree_node_unlink(rdxtree_entry_addr(entry)); ++ ++ llsync_assign_ptr(tree->root, entry); ++ rdxtree_node_schedule_destruction(node); ++ } ++} ++ ++static int ++rdxtree_grow(struct rdxtree *tree, unsigned long long key) ++{ ++ struct rdxtree_node *root, *node; ++ unsigned int new_height; ++ int error; ++ ++ new_height = tree->height + 1; ++ ++ while (key > rdxtree_max_key(new_height)) ++ new_height++; ++ ++ if (tree->root == NULL) { ++ tree->height = new_height; ++ return ERR_SUCCESS; ++ } ++ ++ root = rdxtree_entry_addr(tree->root); ++ ++ do { ++ error = rdxtree_node_create(&node, tree->height); ++ ++ if (error) { ++ rdxtree_shrink(tree); ++ return error; ++ } ++ ++ if (tree->height == 0) ++ rdxtree_node_bm_clear(node, 0); ++ else { ++ rdxtree_node_link(root, node, 0); ++ ++ if (rdxtree_node_bm_empty(root)) ++ rdxtree_node_bm_clear(node, 0); ++ } ++ ++ rdxtree_node_insert(node, 0, tree->root); ++ tree->height++; ++ llsync_assign_ptr(tree->root, rdxtree_node_to_entry(node)); ++ root = node; ++ } while (new_height > tree->height); ++ ++ return ERR_SUCCESS; ++} ++ ++static void ++rdxtree_cleanup(struct rdxtree *tree, struct rdxtree_node *node) ++{ ++ struct rdxtree_node *prev; ++ ++ for (;;) { ++ if (likely(!rdxtree_node_empty(node))) { ++ if (unlikely(node->parent == NULL)) ++ rdxtree_shrink(tree); ++ ++ break; ++ } ++ ++ if (node->parent == NULL) { ++ tree->height = 0; ++ llsync_assign_ptr(tree->root, NULL); ++ rdxtree_node_schedule_destruction(node); ++ break; ++ } ++ ++ prev = node; ++ node = node->parent; ++ rdxtree_node_unlink(prev); ++ rdxtree_node_remove(node, prev->index); ++ rdxtree_node_schedule_destruction(prev); ++ } ++} ++ ++static void ++rdxtree_insert_bm_clear(struct rdxtree_node *node, unsigned int index) ++{ ++ for (;;) { ++ rdxtree_node_bm_clear(node, index); ++ ++ if (!rdxtree_node_full(node) || (node->parent == NULL)) ++ break; ++ ++ index = node->index; ++ node = node->parent; ++ } ++} ++ ++int ++rdxtree_insert_common(struct rdxtree *tree, unsigned long long key, ++ void *ptr, void ***slotp) ++{ ++ struct rdxtree_node *node, *prev; ++ unsigned int height, shift, index = index; ++ int error; ++ ++ assert(ptr != NULL); ++ assert(rdxtree_check_alignment(ptr)); ++ ++ if (unlikely(key > rdxtree_max_key(tree->height))) { ++ error = rdxtree_grow(tree, key); ++ ++ if (error) ++ return error; ++ } ++ ++ height = tree->height; ++ ++ if (unlikely(height == 0)) { ++ if (tree->root != NULL) ++ return ERR_BUSY; ++ ++ llsync_assign_ptr(tree->root, ptr); ++ ++ if (slotp != NULL) ++ *slotp = &tree->root; ++ ++ return ERR_SUCCESS; ++ } ++ ++ node = rdxtree_entry_addr(tree->root); ++ shift = (height - 1) * RDXTREE_RADIX; ++ prev = NULL; ++ ++ do { ++ if (node == NULL) { ++ error = rdxtree_node_create(&node, height - 1); ++ ++ if (error) { ++ if (prev == NULL) ++ tree->height = 0; ++ else ++ rdxtree_cleanup(tree, prev); ++ ++ return error; ++ } ++ ++ if (prev == NULL) ++ llsync_assign_ptr(tree->root, rdxtree_node_to_entry(node)); ++ else { ++ rdxtree_node_link(node, prev, index); ++ rdxtree_node_insert_node(prev, index, node); ++ } ++ } ++ ++ prev = node; ++ index = (unsigned int)(key >> shift) & RDXTREE_RADIX_MASK; ++ node = rdxtree_entry_addr(prev->entries[index]); ++ shift -= RDXTREE_RADIX; ++ height--; ++ } while (height > 0); ++ ++ if (unlikely(node != NULL)) ++ return ERR_BUSY; ++ ++ rdxtree_node_insert(prev, index, ptr); ++ rdxtree_insert_bm_clear(prev, index); ++ ++ if (slotp != NULL) ++ *slotp = &prev->entries[index]; ++ ++ return ERR_SUCCESS; ++} ++ ++int ++rdxtree_insert_alloc_common(struct rdxtree *tree, void *ptr, ++ unsigned long long *keyp, void ***slotp) ++{ ++ struct rdxtree_node *node, *prev; ++ unsigned long long key; ++ unsigned int height, shift, index = index; ++ int error; ++ ++ assert(ptr != NULL); ++ assert(rdxtree_check_alignment(ptr)); ++ ++ height = tree->height; ++ ++ if (unlikely(height == 0)) { ++ if (tree->root == NULL) { ++ llsync_assign_ptr(tree->root, ptr); ++ *keyp = 0; ++ ++ if (slotp != NULL) ++ *slotp = &tree->root; ++ ++ return ERR_SUCCESS; ++ } ++ ++ goto grow; ++ } ++ ++ node = rdxtree_entry_addr(tree->root); ++ key = 0; ++ shift = (height - 1) * RDXTREE_RADIX; ++ prev = NULL; ++ ++ do { ++ if (node == NULL) { ++ error = rdxtree_node_create(&node, height - 1); ++ ++ if (error) { ++ rdxtree_cleanup(tree, prev); ++ return error; ++ } ++ ++ rdxtree_node_link(node, prev, index); ++ rdxtree_node_insert_node(prev, index, node); ++ } ++ ++ prev = node; ++ index = rdxtree_node_bm_first(node); ++ ++ if (index == (unsigned int)-1) ++ goto grow; ++ ++ key |= (unsigned long long)index << shift; ++ node = rdxtree_entry_addr(node->entries[index]); ++ shift -= RDXTREE_RADIX; ++ height--; ++ } while (height > 0); ++ ++ rdxtree_node_insert(prev, index, ptr); ++ rdxtree_insert_bm_clear(prev, index); ++ ++ if (slotp != NULL) ++ *slotp = &prev->entries[index]; ++ ++ goto out; ++ ++grow: ++ key = rdxtree_max_key(height) + 1; ++ error = rdxtree_insert_common(tree, key, ptr, slotp); ++ ++ if (error) ++ return error; ++ ++out: ++ *keyp = key; ++ return ERR_SUCCESS; ++} ++ ++static void ++rdxtree_remove_bm_set(struct rdxtree_node *node, unsigned int index) ++{ ++ do { ++ rdxtree_node_bm_set(node, index); ++ ++ if (node->parent == NULL) ++ break; ++ ++ index = node->index; ++ node = node->parent; ++ } while (!rdxtree_node_bm_is_set(node, index)); ++} ++ ++void * ++rdxtree_remove(struct rdxtree *tree, unsigned long long key) ++{ ++ struct rdxtree_node *node, *prev; ++ unsigned int height, shift, index; ++ ++ height = tree->height; ++ ++ if (unlikely(key > rdxtree_max_key(height))) ++ return NULL; ++ ++ node = rdxtree_entry_addr(tree->root); ++ ++ if (unlikely(height == 0)) { ++ llsync_assign_ptr(tree->root, NULL); ++ return node; ++ } ++ ++ shift = (height - 1) * RDXTREE_RADIX; ++ ++ do { ++ if (node == NULL) ++ return NULL; ++ ++ prev = node; ++ index = (unsigned int)(key >> shift) & RDXTREE_RADIX_MASK; ++ node = rdxtree_entry_addr(node->entries[index]); ++ shift -= RDXTREE_RADIX; ++ height--; ++ } while (height > 0); ++ ++ if (node == NULL) ++ return NULL; ++ ++ rdxtree_node_remove(prev, index); ++ rdxtree_remove_bm_set(prev, index); ++ rdxtree_cleanup(tree, prev); ++ return node; ++} ++ ++void * ++rdxtree_lookup_common(const struct rdxtree *tree, unsigned long long key, ++ int get_slot) ++{ ++ struct rdxtree_node *node, *prev; ++ unsigned int height, shift, index; ++ void *entry; ++ ++ entry = llsync_read_ptr(tree->root); ++ ++ if (entry == NULL) { ++ node = NULL; ++ height = 0; ++ } else { ++ node = rdxtree_entry_addr(entry); ++ height = rdxtree_entry_is_node(entry) ? node->height + 1 : 0; ++ } ++ ++ if (key > rdxtree_max_key(height)) ++ return NULL; ++ ++ if (height == 0) { ++ if (node == NULL) ++ return NULL; ++ ++ return get_slot ? (void *)&tree->root : node; ++ } ++ ++ shift = (height - 1) * RDXTREE_RADIX; ++ ++ do { ++ if (node == NULL) ++ return NULL; ++ ++ prev = node; ++ index = (unsigned int)(key >> shift) & RDXTREE_RADIX_MASK; ++ entry = llsync_read_ptr(node->entries[index]); ++ node = rdxtree_entry_addr(entry); ++ shift -= RDXTREE_RADIX; ++ height--; ++ } while (height > 0); ++ ++ if (node == NULL) ++ return NULL; ++ ++ return get_slot ? (void *)&prev->entries[index] : node; ++} ++ ++void * ++rdxtree_replace_slot(void **slot, void *ptr) ++{ ++ void *old; ++ ++ assert(ptr != NULL); ++ assert(rdxtree_check_alignment(ptr)); ++ ++ old = *slot; ++ assert(old != NULL); ++ assert(rdxtree_check_alignment(old)); ++ llsync_assign_ptr(*slot, ptr); ++ return old; ++} ++ ++static struct rdxtree_node * ++rdxtree_walk(struct rdxtree *tree, struct rdxtree_node *node) ++{ ++ struct rdxtree_node *prev, *child; ++ unsigned int height, index; ++ ++ if (node == NULL) { ++ height = tree->height; ++ node = rdxtree_entry_addr(tree->root); ++ ++ while (height > 1) { ++ node = rdxtree_node_find(node, 0, 0); ++ height--; ++ } ++ ++ return node; ++ } ++ ++ height = 0; ++ ++ for (;;) { ++ prev = node->parent; ++ ++ if (prev == NULL) ++ return NULL; ++ ++ index = node->index; ++ child = rdxtree_node_find(prev, index + 1, 0); ++ ++ if (child != NULL) ++ break; ++ ++ height++; ++ node = prev; ++ } ++ ++ node = child; ++ ++ while (height > 0) { ++ node = rdxtree_node_find(node, 0, 0); ++ height--; ++ } ++ ++ return node; ++} ++ ++void * ++rdxtree_iter_next(struct rdxtree *tree, struct rdxtree_iter *iter) ++{ ++ unsigned int index; ++ ++ if (tree->height == 0) { ++ if (iter->slot != NULL) ++ return NULL; ++ ++ iter->slot = &tree->root; ++ return *iter->slot; ++ } ++ ++ if (iter->node != NULL) { ++ index = iter->slot - ((struct rdxtree_node *)iter->node)->entries; ++ iter->slot = rdxtree_node_find(iter->node, index + 1, 1); ++ } ++ ++ if (iter->slot == NULL) { ++ iter->node = rdxtree_walk(tree, iter->node); ++ ++ if (iter->node != NULL) ++ iter->slot = rdxtree_node_find(iter->node, 0, 1); ++ } ++ ++ if (iter->slot == NULL) ++ return NULL; ++ ++ return *iter->slot; ++} ++ ++void ++rdxtree_remove_all(struct rdxtree *tree) ++{ ++ struct rdxtree_node *node, *parent, *next; ++ unsigned int height, index; ++ ++ height = tree->height; ++ ++ if (height == 0) { ++ if (tree->root != NULL) ++ llsync_assign_ptr(tree->root, NULL); ++ ++ return; ++ } ++ ++ node = rdxtree_walk(tree, NULL); ++ ++ do { ++ next = rdxtree_walk(tree, node); ++ ++ parent = node->parent; ++ ++ if (parent != NULL) { ++ index = node->index; ++ rdxtree_node_remove(parent, index); ++ rdxtree_remove_bm_set(parent, index); ++ rdxtree_cleanup(tree, parent); ++ node->parent = NULL; ++ } ++ ++ rdxtree_node_schedule_destruction(node); ++ ++ node = next; ++ } while (node != NULL); ++} +diff --git a/librdxtree/rdxtree.h b/librdxtree/rdxtree.h +new file mode 100644 +index 0000000..8ccfa25 +--- /dev/null ++++ b/librdxtree/rdxtree.h +@@ -0,0 +1,195 @@ ++/* ++ * Copyright (c) 2013 Richard Braun. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++/* ++ * Copyright (c) 2011 Richard Braun. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * Radix tree. ++ * ++ * In addition to the standard insertion operation, this implementation ++ * can allocate keys for the caller at insertion time. ++ */ ++ ++#ifndef _RDXTREE_H ++#define _RDXTREE_H ++ ++#include <stddef.h> ++ ++/* ++ * Radix tree. ++ */ ++struct rdxtree; ++ ++/* ++ * Radix tree iterator. ++ */ ++struct rdxtree_iter; ++ ++/* ++ * Static tree initializer. ++ */ ++#define RDXTREE_INITIALIZER { 0, NULL } ++ ++#include "rdxtree_i.h" ++ ++/* ++ * Initialize a tree. ++ */ ++static inline void ++rdxtree_init(struct rdxtree *tree) ++{ ++ tree->height = 0; ++ tree->root = NULL; ++} ++ ++/* ++ * Insert a pointer in a tree. ++ * ++ * The ptr parameter must not be NULL. ++ */ ++static inline int ++rdxtree_insert(struct rdxtree *tree, unsigned long long key, void *ptr) ++{ ++ return rdxtree_insert_common(tree, key, ptr, NULL); ++} ++ ++/* ++ * Insert a pointer in a tree and obtain its slot. ++ * ++ * The ptr and slotp parameters must not be NULL. If successful, the slot of ++ * the newly inserted pointer is stored at the address pointed to by the slotp ++ * parameter. ++ */ ++static inline int ++rdxtree_insert_slot(struct rdxtree *tree, unsigned long long key, void *ptr, ++ void ***slotp) ++{ ++ return rdxtree_insert_common(tree, key, ptr, slotp); ++} ++ ++/* ++ * Insert a pointer in a tree, for which a new key is allocated. ++ * ++ * The ptr and keyp parameters must not be NULL. The newly allocated key is ++ * stored at the address pointed to by the keyp parameter. ++ */ ++static inline int ++rdxtree_insert_alloc(struct rdxtree *tree, void *ptr, unsigned long long *keyp) ++{ ++ return rdxtree_insert_alloc_common(tree, ptr, keyp, NULL); ++} ++ ++/* ++ * Insert a pointer in a tree, for which a new key is allocated, and obtain ++ * its slot. ++ * ++ * The ptr, keyp and slotp parameters must not be NULL. The newly allocated ++ * key is stored at the address pointed to by the keyp parameter while the ++ * slot of the inserted pointer is stored at the address pointed to by the ++ * slotp parameter. ++ */ ++static inline int ++rdxtree_insert_alloc_slot(struct rdxtree *tree, void *ptr, ++ unsigned long long *keyp, void ***slotp) ++{ ++ return rdxtree_insert_alloc_common(tree, ptr, keyp, slotp); ++} ++ ++/* ++ * Remove a pointer from a tree. ++ * ++ * The matching pointer is returned if successful, NULL otherwise. ++ */ ++void * rdxtree_remove(struct rdxtree *tree, unsigned long long key); ++ ++/* ++ * Look up a pointer in a tree. ++ * ++ * The matching pointer is returned if successful, NULL otherwise. ++ */ ++static inline void * ++rdxtree_lookup(const struct rdxtree *tree, unsigned long long key) ++{ ++ return rdxtree_lookup_common(tree, key, 0); ++} ++ ++/* ++ * Look up a slot in a tree. ++ * ++ * A slot is a pointer to a stored pointer in a tree. It can be used as ++ * a placeholder for fast replacements to avoid multiple lookups on the same ++ * key. ++ * ++ * A slot for the matching pointer is returned if successful, NULL otherwise. ++ * ++ * See rdxtree_replace_slot(). ++ */ ++static inline void ** ++rdxtree_lookup_slot(const struct rdxtree *tree, unsigned long long key) ++{ ++ return rdxtree_lookup_common(tree, key, 1); ++} ++ ++/* ++ * Replace a pointer in a tree. ++ * ++ * The ptr parameter must not be NULL. The previous pointer is returned. ++ * ++ * See rdxtree_lookup_slot(). ++ */ ++void * rdxtree_replace_slot(void **slot, void *ptr); ++ ++/* ++ * Forge a loop to process all pointers of a tree. ++ */ ++#define rdxtree_for_each(tree, iter, ptr) \ ++for (rdxtree_iter_init(iter), ptr = rdxtree_iter_next(tree, iter); \ ++ ptr != NULL; \ ++ ptr = rdxtree_iter_next(tree, iter)) ++ ++/* ++ * Remove all pointers from a tree. ++ * ++ * The common way to destroy a tree and its pointers is to loop over all ++ * the pointers using rdxtree_for_each(), freeing them, then call this ++ * function. ++ */ ++void rdxtree_remove_all(struct rdxtree *tree); ++ ++#endif /* _RDXTREE_H */ +diff --git a/librdxtree/rdxtree_i.h b/librdxtree/rdxtree_i.h +new file mode 100644 +index 0000000..4761beb +--- /dev/null ++++ b/librdxtree/rdxtree_i.h +@@ -0,0 +1,65 @@ ++/* ++ * Copyright (c) 2013 Richard Braun. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef _RDXTREE_I_H ++#define _RDXTREE_I_H ++ ++/* ++ * Radix tree. ++ */ ++struct rdxtree { ++ unsigned int height; ++ void *root; ++}; ++ ++/* ++ * Radix tree iterator. ++ */ ++struct rdxtree_iter { ++ void *node; ++ void **slot; ++}; ++ ++/* ++ * Initialize an iterator. ++ */ ++static inline void ++rdxtree_iter_init(struct rdxtree_iter *iter) ++{ ++ iter->node = NULL; ++ iter->slot = NULL; ++} ++ ++int rdxtree_insert_common(struct rdxtree *tree, unsigned long long key, ++ void *ptr, void ***slotp); ++ ++int rdxtree_insert_alloc_common(struct rdxtree *tree, void *ptr, ++ unsigned long long *keyp, void ***slotp); ++ ++void * rdxtree_lookup_common(const struct rdxtree *tree, unsigned long long key, ++ int get_slot); ++ ++/* ++ * Walk over pointers in a tree. ++ * ++ * Move the iterator to the next pointer in the given tree. ++ * ++ * The next pointer is returned if there is one, NULL otherwise. ++ */ ++void * rdxtree_iter_next(struct rdxtree *tree, struct rdxtree_iter *iter); ++ ++#endif /* _RDXTREE_I_H */ +-- +2.0.0.rc2 + |