diff options
Diffstat (limited to 'debian/patches/0011-librdxtree-add-a-radix-tree-implementation.patch')
-rw-r--r-- | debian/patches/0011-librdxtree-add-a-radix-tree-implementation.patch | 1439 |
1 files changed, 0 insertions, 1439 deletions
diff --git a/debian/patches/0011-librdxtree-add-a-radix-tree-implementation.patch b/debian/patches/0011-librdxtree-add-a-radix-tree-implementation.patch deleted file mode 100644 index 5f784ae8..00000000 --- a/debian/patches/0011-librdxtree-add-a-radix-tree-implementation.patch +++ /dev/null @@ -1,1439 +0,0 @@ -From faf8b98c69b66785246651ed3852e98243b4db0c 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 11/27] 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 - |