003 File Manager
Current Path:
/usr/src/sys/kern
usr
/
src
/
sys
/
kern
/
📁
..
📄
Make.tags.inc
(2.13 KB)
📄
Makefile
(302 B)
📄
bus_if.m
(26.31 KB)
📄
capabilities.conf
(13.67 KB)
📄
clock_if.m
(1.7 KB)
📄
cpufreq_if.m
(2.27 KB)
📄
device_if.m
(10.41 KB)
📄
firmw.S
(2.15 KB)
📄
genassym.sh
(1.11 KB)
📄
genoffset.c
(1.68 KB)
📄
genoffset.sh
(3.58 KB)
📄
imgact_aout.c
(9.45 KB)
📄
imgact_binmisc.c
(18.64 KB)
📄
imgact_elf.c
(76.32 KB)
📄
imgact_elf32.c
(1.47 KB)
📄
imgact_elf64.c
(1.47 KB)
📄
imgact_shell.c
(8.41 KB)
📄
init_main.c
(24.31 KB)
📄
init_sysent.c
(95.3 KB)
📄
kern_acct.c
(19.03 KB)
📄
kern_alq.c
(24.97 KB)
📄
kern_clock.c
(21.12 KB)
📄
kern_clocksource.c
(23.34 KB)
📄
kern_condvar.c
(11.28 KB)
📄
kern_conf.c
(36.14 KB)
📄
kern_cons.c
(15.75 KB)
📄
kern_context.c
(3.59 KB)
📄
kern_cpu.c
(30.77 KB)
📄
kern_cpuset.c
(59.78 KB)
📄
kern_ctf.c
(8.73 KB)
📄
kern_descrip.c
(112.87 KB)
📄
kern_dtrace.c
(2.94 KB)
📄
kern_dump.c
(8.51 KB)
📄
kern_environment.c
(22.75 KB)
📄
kern_et.c
(7.1 KB)
📄
kern_event.c
(62.49 KB)
📄
kern_exec.c
(46.67 KB)
📄
kern_exit.c
(34.61 KB)
📄
kern_fail.c
(29.32 KB)
📄
kern_ffclock.c
(12.66 KB)
📄
kern_fork.c
(28.29 KB)
📄
kern_hhook.c
(13.58 KB)
📄
kern_idle.c
(2.74 KB)
📄
kern_intr.c
(40.44 KB)
📄
kern_jail.c
(112.67 KB)
📄
kern_kcov.c
(15.32 KB)
📄
kern_khelp.c
(9.45 KB)
📄
kern_kthread.c
(11.8 KB)
📄
kern_ktr.c
(11.93 KB)
📄
kern_ktrace.c
(31.41 KB)
📄
kern_linker.c
(54.3 KB)
📄
kern_lock.c
(46.99 KB)
📄
kern_lockf.c
(64.46 KB)
📄
kern_lockstat.c
(3.8 KB)
📄
kern_loginclass.c
(6.69 KB)
📄
kern_malloc.c
(37.09 KB)
📄
kern_mbuf.c
(43.16 KB)
📄
kern_mib.c
(24.26 KB)
📄
kern_module.c
(11.05 KB)
📄
kern_mtxpool.c
(5.82 KB)
📄
kern_mutex.c
(33.62 KB)
📄
kern_ntptime.c
(32.49 KB)
📄
kern_osd.c
(12.37 KB)
📄
kern_physio.c
(5.74 KB)
📄
kern_pmc.c
(8.89 KB)
📄
kern_poll.c
(15.86 KB)
📄
kern_priv.c
(9.14 KB)
📄
kern_proc.c
(80.01 KB)
📄
kern_procctl.c
(19.48 KB)
📄
kern_prot.c
(57.94 KB)
📄
kern_racct.c
(34.01 KB)
📄
kern_rangelock.c
(8.67 KB)
📄
kern_rctl.c
(53.87 KB)
📄
kern_resource.c
(36.66 KB)
📄
kern_rmlock.c
(28.27 KB)
📄
kern_rwlock.c
(40.72 KB)
📄
kern_sdt.c
(2.05 KB)
📄
kern_sema.c
(4.85 KB)
📄
kern_sendfile.c
(33.97 KB)
📄
kern_sharedpage.c
(10.37 KB)
📄
kern_shutdown.c
(43.34 KB)
📄
kern_sig.c
(101.89 KB)
📄
kern_switch.c
(13.85 KB)
📄
kern_sx.c
(40.27 KB)
📄
kern_synch.c
(18.17 KB)
📄
kern_syscalls.c
(6.74 KB)
📄
kern_sysctl.c
(67.24 KB)
📄
kern_tc.c
(55.73 KB)
📄
kern_thr.c
(14.14 KB)
📄
kern_thread.c
(41.75 KB)
📄
kern_time.c
(40.89 KB)
📄
kern_timeout.c
(43.08 KB)
📄
kern_tslog.c
(3.44 KB)
📄
kern_ubsan.c
(50.74 KB)
📄
kern_umtx.c
(107.14 KB)
📄
kern_uuid.c
(11.68 KB)
📄
kern_xxx.c
(10.44 KB)
📄
ksched.c
(6.56 KB)
📄
link_elf.c
(47.99 KB)
📄
link_elf_obj.c
(44.41 KB)
📄
linker_if.m
(3.96 KB)
📄
makesyscalls.sh
(23.57 KB)
📄
md4c.c
(7.89 KB)
📄
md5c.c
(9.56 KB)
📄
msi_if.m
(2.48 KB)
📄
p1003_1b.c
(8.84 KB)
📄
pic_if.m
(3.9 KB)
📄
posix4_mib.c
(5.59 KB)
📄
sched_4bsd.c
(45.03 KB)
📄
sched_ule.c
(82.65 KB)
📄
serdev_if.m
(3.49 KB)
📄
stack_protector.c
(613 B)
📄
subr_acl_nfs4.c
(37.42 KB)
📄
subr_acl_posix1e.c
(17.71 KB)
📄
subr_atomic64.c
(3.97 KB)
📄
subr_autoconf.c
(7.7 KB)
📄
subr_blist.c
(31.88 KB)
📄
subr_boot.c
(5.8 KB)
📄
subr_bufring.c
(2.21 KB)
📄
subr_bus.c
(145.4 KB)
📄
subr_bus_dma.c
(19.67 KB)
📄
subr_busdma_bufalloc.c
(5.24 KB)
📄
subr_capability.c
(11.93 KB)
📄
subr_clock.c
(10.61 KB)
📄
subr_compressor.c
(13.11 KB)
📄
subr_counter.c
(4.44 KB)
📄
subr_coverage.c
(6.17 KB)
📄
subr_csan.c
(25.39 KB)
📄
subr_devmap.c
(9.8 KB)
📄
subr_devstat.c
(16.21 KB)
📄
subr_disk.c
(8.54 KB)
📄
subr_dummy_vdso_tc.c
(1.7 KB)
📄
subr_early.c
(2.26 KB)
📄
subr_epoch.c
(25.02 KB)
📄
subr_eventhandler.c
(9.17 KB)
📄
subr_fattime.c
(9.98 KB)
📄
subr_filter.c
(12.2 KB)
📄
subr_firmware.c
(13.88 KB)
📄
subr_gtaskqueue.c
(20.19 KB)
📄
subr_hash.c
(4.8 KB)
📄
subr_hints.c
(12.87 KB)
📄
subr_intr.c
(40.61 KB)
📄
subr_kdb.c
(16.13 KB)
📄
subr_kobj.c
(7.1 KB)
📄
subr_lock.c
(18.81 KB)
📄
subr_log.c
(7.64 KB)
📄
subr_mchain.c
(11.06 KB)
📄
subr_module.c
(12.98 KB)
📄
subr_msgbuf.c
(10.6 KB)
📄
subr_param.c
(10.93 KB)
📄
subr_pcpu.c
(10.18 KB)
📄
subr_pctrie.c
(20.99 KB)
📄
subr_physmem.c
(11.52 KB)
📄
subr_pidctrl.c
(5.43 KB)
📄
subr_power.c
(3.13 KB)
📄
subr_prf.c
(27.42 KB)
📄
subr_prng.c
(3.36 KB)
📄
subr_prof.c
(15.43 KB)
📄
subr_rangeset.c
(8.5 KB)
📄
subr_rman.c
(27.61 KB)
📄
subr_rtc.c
(11.42 KB)
📄
subr_sbuf.c
(20.53 KB)
📄
subr_scanf.c
(15.59 KB)
📄
subr_sfbuf.c
(6.17 KB)
📄
subr_sglist.c
(22.83 KB)
📄
subr_sleepqueue.c
(39.43 KB)
📄
subr_smp.c
(31.62 KB)
📄
subr_smr.c
(20.17 KB)
📄
subr_stack.c
(6.47 KB)
📄
subr_stats.c
(103.01 KB)
📄
subr_syscall.c
(7.98 KB)
📄
subr_taskqueue.c
(21.1 KB)
📄
subr_terminal.c
(15.52 KB)
📄
subr_trap.c
(10.87 KB)
📄
subr_turnstile.c
(35.58 KB)
📄
subr_uio.c
(11.38 KB)
📄
subr_unit.c
(22.97 KB)
📄
subr_vmem.c
(43.25 KB)
📄
subr_witness.c
(84.59 KB)
📄
sys_capability.c
(15.06 KB)
📄
sys_eventfd.c
(8.42 KB)
📄
sys_generic.c
(44.22 KB)
📄
sys_getrandom.c
(4.21 KB)
📄
sys_pipe.c
(45.14 KB)
📄
sys_procdesc.c
(14.57 KB)
📄
sys_process.c
(30.73 KB)
📄
sys_socket.c
(20.11 KB)
📄
syscalls.c
(22.73 KB)
📄
syscalls.master
(60.26 KB)
📄
systrace_args.c
(178.49 KB)
📄
sysv_ipc.c
(6.53 KB)
📄
sysv_msg.c
(48.65 KB)
📄
sysv_sem.c
(49.85 KB)
📄
sysv_shm.c
(43.93 KB)
📄
tty.c
(55.14 KB)
📄
tty_compat.c
(11.46 KB)
📄
tty_info.c
(9.93 KB)
📄
tty_inq.c
(12.22 KB)
📄
tty_outq.c
(8.74 KB)
📄
tty_pts.c
(19.74 KB)
📄
tty_tty.c
(2.83 KB)
📄
tty_ttydisc.c
(28.6 KB)
📄
uipc_accf.c
(8.07 KB)
📄
uipc_debug.c
(12.42 KB)
📄
uipc_domain.c
(13.13 KB)
📄
uipc_ktls.c
(55.7 KB)
📄
uipc_mbuf.c
(52.45 KB)
📄
uipc_mbuf2.c
(12.64 KB)
📄
uipc_mbufhash.c
(4.9 KB)
📄
uipc_mqueue.c
(64.64 KB)
📄
uipc_sem.c
(25.18 KB)
📄
uipc_shm.c
(50.47 KB)
📄
uipc_sockbuf.c
(42.9 KB)
📄
uipc_socket.c
(110.61 KB)
📄
uipc_syscalls.c
(35.94 KB)
📄
uipc_usrreq.c
(75.11 KB)
📄
vfs_acl.c
(14.5 KB)
📄
vfs_aio.c
(76.32 KB)
📄
vfs_bio.c
(145.39 KB)
📄
vfs_cache.c
(143.09 KB)
📄
vfs_cluster.c
(28.36 KB)
📄
vfs_default.c
(33.16 KB)
📄
vfs_export.c
(14.55 KB)
📄
vfs_extattr.c
(17.91 KB)
📄
vfs_hash.c
(6 KB)
📄
vfs_init.c
(15.86 KB)
📄
vfs_lookup.c
(45.48 KB)
📄
vfs_mount.c
(62.58 KB)
📄
vfs_mountroot.c
(26.23 KB)
📄
vfs_subr.c
(167.52 KB)
📄
vfs_syscalls.c
(106.86 KB)
📄
vfs_vnops.c
(86.28 KB)
📄
vnode_if.src
(13.66 KB)
Editing: subr_pctrie.c
/*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2013 EMC Corp. * Copyright (c) 2011 Jeffrey Roberson <jeff@freebsd.org> * Copyright (c) 2008 Mayur Shardul <mayur.shardul@gmail.com> * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. * */ /* * Path-compressed radix trie implementation. * * The implementation takes into account the following rationale: * - Size of the nodes should be as small as possible but still big enough * to avoid a large maximum depth for the trie. This is a balance * between the necessity to not wire too much physical memory for the nodes * and the necessity to avoid too much cache pollution during the trie * operations. * - There is not a huge bias toward the number of lookup operations over * the number of insert and remove operations. This basically implies * that optimizations supposedly helping one operation but hurting the * other might be carefully evaluated. * - On average not many nodes are expected to be fully populated, hence * level compression may just complicate things. */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/pctrie.h> #include <sys/proc.h> /* smr.h depends on struct thread. */ #include <sys/smr.h> #include <sys/smr_types.h> #ifdef DDB #include <ddb/ddb.h> #endif #define PCTRIE_MASK (PCTRIE_COUNT - 1) #define PCTRIE_LIMIT (howmany(sizeof(uint64_t) * NBBY, PCTRIE_WIDTH) - 1) /* Flag bits stored in node pointers. */ #define PCTRIE_ISLEAF 0x1 #define PCTRIE_FLAGS 0x1 #define PCTRIE_PAD PCTRIE_FLAGS /* Returns one unit associated with specified level. */ #define PCTRIE_UNITLEVEL(lev) \ ((uint64_t)1 << ((lev) * PCTRIE_WIDTH)) struct pctrie_node; typedef SMR_POINTER(struct pctrie_node *) smr_pctnode_t; struct pctrie_node { uint64_t pn_owner; /* Owner of record. */ uint16_t pn_count; /* Valid children. */ uint8_t pn_clev; /* Current level. */ int8_t pn_last; /* Zero last ptr. */ smr_pctnode_t pn_child[PCTRIE_COUNT]; /* Child nodes. */ }; enum pctrie_access { PCTRIE_SMR, PCTRIE_LOCKED, PCTRIE_UNSERIALIZED }; static __inline void pctrie_node_store(smr_pctnode_t *p, void *val, enum pctrie_access access); /* * Allocate a node. Pre-allocation should ensure that the request * will always be satisfied. */ static struct pctrie_node * pctrie_node_get(struct pctrie *ptree, pctrie_alloc_t allocfn, uint64_t owner, uint16_t count, uint16_t clevel) { struct pctrie_node *node; node = allocfn(ptree); if (node == NULL) return (NULL); /* * We want to clear the last child pointer after the final section * has exited so lookup can not return false negatives. It is done * here because it will be cache-cold in the dtor callback. */ if (node->pn_last != 0) { pctrie_node_store(&node->pn_child[node->pn_last - 1], NULL, PCTRIE_UNSERIALIZED); node->pn_last = 0; } node->pn_owner = owner; node->pn_count = count; node->pn_clev = clevel; return (node); } /* * Free radix node. */ static __inline void pctrie_node_put(struct pctrie *ptree, struct pctrie_node *node, pctrie_free_t freefn, int8_t last) { #ifdef INVARIANTS int slot; KASSERT(node->pn_count == 0, ("pctrie_node_put: node %p has %d children", node, node->pn_count)); for (slot = 0; slot < PCTRIE_COUNT; slot++) { if (slot == last) continue; KASSERT(smr_unserialized_load(&node->pn_child[slot], true) == NULL, ("pctrie_node_put: node %p has a child", node)); } #endif node->pn_last = last + 1; freefn(ptree, node); } /* * Return the position in the array for a given level. */ static __inline int pctrie_slot(uint64_t index, uint16_t level) { return ((index >> (level * PCTRIE_WIDTH)) & PCTRIE_MASK); } /* Trims the key after the specified level. */ static __inline uint64_t pctrie_trimkey(uint64_t index, uint16_t level) { uint64_t ret; ret = index; if (level > 0) { ret >>= level * PCTRIE_WIDTH; ret <<= level * PCTRIE_WIDTH; } return (ret); } /* * Fetch a node pointer from a slot. */ static __inline struct pctrie_node * pctrie_node_load(smr_pctnode_t *p, smr_t smr, enum pctrie_access access) { switch (access) { case PCTRIE_UNSERIALIZED: return (smr_unserialized_load(p, true)); case PCTRIE_LOCKED: return (smr_serialized_load(p, true)); case PCTRIE_SMR: return (smr_entered_load(p, smr)); } __assert_unreachable(); } static __inline void pctrie_node_store(smr_pctnode_t *p, void *v, enum pctrie_access access) { switch (access) { case PCTRIE_UNSERIALIZED: smr_unserialized_store(p, v, true); break; case PCTRIE_LOCKED: smr_serialized_store(p, v, true); break; case PCTRIE_SMR: panic("%s: Not supported in SMR section.", __func__); break; default: __assert_unreachable(); break; } } /* * Get the root node for a tree. */ static __inline struct pctrie_node * pctrie_root_load(struct pctrie *ptree, smr_t smr, enum pctrie_access access) { return (pctrie_node_load((smr_pctnode_t *)&ptree->pt_root, smr, access)); } /* * Set the root node for a tree. */ static __inline void pctrie_root_store(struct pctrie *ptree, struct pctrie_node *node, enum pctrie_access access) { pctrie_node_store((smr_pctnode_t *)&ptree->pt_root, node, access); } /* * Returns TRUE if the specified node is a leaf and FALSE otherwise. */ static __inline bool pctrie_isleaf(struct pctrie_node *node) { return (((uintptr_t)node & PCTRIE_ISLEAF) != 0); } /* * Returns the associated val extracted from node. */ static __inline uint64_t * pctrie_toval(struct pctrie_node *node) { return ((uint64_t *)((uintptr_t)node & ~PCTRIE_FLAGS)); } /* * Adds the val as a child of the provided node. */ static __inline void pctrie_addval(struct pctrie_node *node, uint64_t index, uint16_t clev, uint64_t *val, enum pctrie_access access) { int slot; slot = pctrie_slot(index, clev); pctrie_node_store(&node->pn_child[slot], (void *)((uintptr_t)val | PCTRIE_ISLEAF), access); } /* * Returns the slot where two keys differ. * It cannot accept 2 equal keys. */ static __inline uint16_t pctrie_keydiff(uint64_t index1, uint64_t index2) { uint16_t clev; KASSERT(index1 != index2, ("%s: passing the same key value %jx", __func__, (uintmax_t)index1)); index1 ^= index2; for (clev = PCTRIE_LIMIT;; clev--) if (pctrie_slot(index1, clev) != 0) return (clev); } /* * Returns TRUE if it can be determined that key does not belong to the * specified node. Otherwise, returns FALSE. */ static __inline bool pctrie_keybarr(struct pctrie_node *node, uint64_t idx) { if (node->pn_clev < PCTRIE_LIMIT) { idx = pctrie_trimkey(idx, node->pn_clev + 1); return (idx != node->pn_owner); } return (false); } /* * Internal helper for pctrie_reclaim_allnodes(). * This function is recursive. */ static void pctrie_reclaim_allnodes_int(struct pctrie *ptree, struct pctrie_node *node, pctrie_free_t freefn) { struct pctrie_node *child; int slot; KASSERT(node->pn_count <= PCTRIE_COUNT, ("pctrie_reclaim_allnodes_int: bad count in node %p", node)); for (slot = 0; node->pn_count != 0; slot++) { child = pctrie_node_load(&node->pn_child[slot], NULL, PCTRIE_UNSERIALIZED); if (child == NULL) continue; if (!pctrie_isleaf(child)) pctrie_reclaim_allnodes_int(ptree, child, freefn); pctrie_node_store(&node->pn_child[slot], NULL, PCTRIE_UNSERIALIZED); node->pn_count--; } pctrie_node_put(ptree, node, freefn, -1); } /* * pctrie node zone initializer. */ int pctrie_zone_init(void *mem, int size __unused, int flags __unused) { struct pctrie_node *node; node = mem; node->pn_last = 0; memset(node->pn_child, 0, sizeof(node->pn_child)); return (0); } size_t pctrie_node_size(void) { return (sizeof(struct pctrie_node)); } /* * Inserts the key-value pair into the trie. * Panics if the key already exists. */ int pctrie_insert(struct pctrie *ptree, uint64_t *val, pctrie_alloc_t allocfn) { uint64_t index, newind; struct pctrie_node *node, *tmp; smr_pctnode_t *parentp; uint64_t *m; int slot; uint16_t clev; index = *val; /* * The owner of record for root is not really important because it * will never be used. */ node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); if (node == NULL) { ptree->pt_root = (uintptr_t)val | PCTRIE_ISLEAF; return (0); } parentp = (smr_pctnode_t *)&ptree->pt_root; for (;;) { if (pctrie_isleaf(node)) { m = pctrie_toval(node); if (*m == index) panic("%s: key %jx is already present", __func__, (uintmax_t)index); clev = pctrie_keydiff(*m, index); tmp = pctrie_node_get(ptree, allocfn, pctrie_trimkey(index, clev + 1), 2, clev); if (tmp == NULL) return (ENOMEM); /* These writes are not yet visible due to ordering. */ pctrie_addval(tmp, index, clev, val, PCTRIE_UNSERIALIZED); pctrie_addval(tmp, *m, clev, m, PCTRIE_UNSERIALIZED); /* Synchronize to make leaf visible. */ pctrie_node_store(parentp, tmp, PCTRIE_LOCKED); return (0); } else if (pctrie_keybarr(node, index)) break; slot = pctrie_slot(index, node->pn_clev); parentp = &node->pn_child[slot]; tmp = pctrie_node_load(parentp, NULL, PCTRIE_LOCKED); if (tmp == NULL) { node->pn_count++; pctrie_addval(node, index, node->pn_clev, val, PCTRIE_LOCKED); return (0); } node = tmp; } /* * A new node is needed because the right insertion level is reached. * Setup the new intermediate node and add the 2 children: the * new object and the older edge. */ newind = node->pn_owner; clev = pctrie_keydiff(newind, index); tmp = pctrie_node_get(ptree, allocfn, pctrie_trimkey(index, clev + 1), 2, clev); if (tmp == NULL) return (ENOMEM); slot = pctrie_slot(newind, clev); /* These writes are not yet visible due to ordering. */ pctrie_addval(tmp, index, clev, val, PCTRIE_UNSERIALIZED); pctrie_node_store(&tmp->pn_child[slot], node, PCTRIE_UNSERIALIZED); /* Synchronize to make the above visible. */ pctrie_node_store(parentp, tmp, PCTRIE_LOCKED); return (0); } /* * Returns the value stored at the index. If the index is not present, * NULL is returned. */ static __always_inline uint64_t * _pctrie_lookup(struct pctrie *ptree, uint64_t index, smr_t smr, enum pctrie_access access) { struct pctrie_node *node; uint64_t *m; int slot; node = pctrie_root_load(ptree, smr, access); while (node != NULL) { if (pctrie_isleaf(node)) { m = pctrie_toval(node); if (*m == index) return (m); break; } if (pctrie_keybarr(node, index)) break; slot = pctrie_slot(index, node->pn_clev); node = pctrie_node_load(&node->pn_child[slot], smr, access); } return (NULL); } /* * Returns the value stored at the index, assuming access is externally * synchronized by a lock. * * If the index is not present, NULL is returned. */ uint64_t * pctrie_lookup(struct pctrie *ptree, uint64_t index) { return (_pctrie_lookup(ptree, index, NULL, PCTRIE_LOCKED)); } /* * Returns the value stored at the index without requiring an external lock. * * If the index is not present, NULL is returned. */ uint64_t * pctrie_lookup_unlocked(struct pctrie *ptree, uint64_t index, smr_t smr) { uint64_t *res; smr_enter(smr); res = _pctrie_lookup(ptree, index, smr, PCTRIE_SMR); smr_exit(smr); return (res); } /* * Look up the nearest entry at a position bigger than or equal to index, * assuming access is externally synchronized by a lock. */ uint64_t * pctrie_lookup_ge(struct pctrie *ptree, uint64_t index) { struct pctrie_node *stack[PCTRIE_LIMIT]; uint64_t inc; uint64_t *m; struct pctrie_node *child, *node; #ifdef INVARIANTS int loops = 0; #endif unsigned tos; int slot; node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); if (node == NULL) return (NULL); else if (pctrie_isleaf(node)) { m = pctrie_toval(node); if (*m >= index) return (m); else return (NULL); } tos = 0; for (;;) { /* * If the keys differ before the current bisection node, * then the search key might rollback to the earliest * available bisection node or to the smallest key * in the current node (if the owner is greater than the * search key). */ if (pctrie_keybarr(node, index)) { if (index > node->pn_owner) { ascend: KASSERT(++loops < 1000, ("pctrie_lookup_ge: too many loops")); /* * Pop nodes from the stack until either the * stack is empty or a node that could have a * matching descendant is found. */ do { if (tos == 0) return (NULL); node = stack[--tos]; } while (pctrie_slot(index, node->pn_clev) == (PCTRIE_COUNT - 1)); /* * The following computation cannot overflow * because index's slot at the current level * is less than PCTRIE_COUNT - 1. */ index = pctrie_trimkey(index, node->pn_clev); index += PCTRIE_UNITLEVEL(node->pn_clev); } else index = node->pn_owner; KASSERT(!pctrie_keybarr(node, index), ("pctrie_lookup_ge: keybarr failed")); } slot = pctrie_slot(index, node->pn_clev); child = pctrie_node_load(&node->pn_child[slot], NULL, PCTRIE_LOCKED); if (pctrie_isleaf(child)) { m = pctrie_toval(child); if (*m >= index) return (m); } else if (child != NULL) goto descend; /* * Look for an available edge or val within the current * bisection node. */ if (slot < (PCTRIE_COUNT - 1)) { inc = PCTRIE_UNITLEVEL(node->pn_clev); index = pctrie_trimkey(index, node->pn_clev); do { index += inc; slot++; child = pctrie_node_load(&node->pn_child[slot], NULL, PCTRIE_LOCKED); if (pctrie_isleaf(child)) { m = pctrie_toval(child); if (*m >= index) return (m); } else if (child != NULL) goto descend; } while (slot < (PCTRIE_COUNT - 1)); } KASSERT(child == NULL || pctrie_isleaf(child), ("pctrie_lookup_ge: child is radix node")); /* * If a value or edge greater than the search slot is not found * in the current node, ascend to the next higher-level node. */ goto ascend; descend: KASSERT(node->pn_clev > 0, ("pctrie_lookup_ge: pushing leaf's parent")); KASSERT(tos < PCTRIE_LIMIT, ("pctrie_lookup_ge: stack overflow")); stack[tos++] = node; node = child; } } /* * Look up the nearest entry at a position less than or equal to index, * assuming access is externally synchronized by a lock. */ uint64_t * pctrie_lookup_le(struct pctrie *ptree, uint64_t index) { struct pctrie_node *stack[PCTRIE_LIMIT]; uint64_t inc; uint64_t *m; struct pctrie_node *child, *node; #ifdef INVARIANTS int loops = 0; #endif unsigned tos; int slot; node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); if (node == NULL) return (NULL); else if (pctrie_isleaf(node)) { m = pctrie_toval(node); if (*m <= index) return (m); else return (NULL); } tos = 0; for (;;) { /* * If the keys differ before the current bisection node, * then the search key might rollback to the earliest * available bisection node or to the largest key * in the current node (if the owner is smaller than the * search key). */ if (pctrie_keybarr(node, index)) { if (index > node->pn_owner) { index = node->pn_owner + PCTRIE_COUNT * PCTRIE_UNITLEVEL(node->pn_clev); } else { ascend: KASSERT(++loops < 1000, ("pctrie_lookup_le: too many loops")); /* * Pop nodes from the stack until either the * stack is empty or a node that could have a * matching descendant is found. */ do { if (tos == 0) return (NULL); node = stack[--tos]; } while (pctrie_slot(index, node->pn_clev) == 0); /* * The following computation cannot overflow * because index's slot at the current level * is greater than 0. */ index = pctrie_trimkey(index, node->pn_clev); } index--; KASSERT(!pctrie_keybarr(node, index), ("pctrie_lookup_le: keybarr failed")); } slot = pctrie_slot(index, node->pn_clev); child = pctrie_node_load(&node->pn_child[slot], NULL, PCTRIE_LOCKED); if (pctrie_isleaf(child)) { m = pctrie_toval(child); if (*m <= index) return (m); } else if (child != NULL) goto descend; /* * Look for an available edge or value within the current * bisection node. */ if (slot > 0) { inc = PCTRIE_UNITLEVEL(node->pn_clev); index |= inc - 1; do { index -= inc; slot--; child = pctrie_node_load(&node->pn_child[slot], NULL, PCTRIE_LOCKED); if (pctrie_isleaf(child)) { m = pctrie_toval(child); if (*m <= index) return (m); } else if (child != NULL) goto descend; } while (slot > 0); } KASSERT(child == NULL || pctrie_isleaf(child), ("pctrie_lookup_le: child is radix node")); /* * If a value or edge smaller than the search slot is not found * in the current node, ascend to the next higher-level node. */ goto ascend; descend: KASSERT(node->pn_clev > 0, ("pctrie_lookup_le: pushing leaf's parent")); KASSERT(tos < PCTRIE_LIMIT, ("pctrie_lookup_le: stack overflow")); stack[tos++] = node; node = child; } } /* * Remove the specified index from the tree. * Panics if the key is not present. */ void pctrie_remove(struct pctrie *ptree, uint64_t index, pctrie_free_t freefn) { struct pctrie_node *node, *parent, *tmp; uint64_t *m; int i, slot; node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); if (pctrie_isleaf(node)) { m = pctrie_toval(node); if (*m != index) panic("%s: invalid key found", __func__); pctrie_root_store(ptree, NULL, PCTRIE_LOCKED); return; } parent = NULL; for (;;) { if (node == NULL) panic("pctrie_remove: impossible to locate the key"); slot = pctrie_slot(index, node->pn_clev); tmp = pctrie_node_load(&node->pn_child[slot], NULL, PCTRIE_LOCKED); if (pctrie_isleaf(tmp)) { m = pctrie_toval(tmp); if (*m != index) panic("%s: invalid key found", __func__); pctrie_node_store(&node->pn_child[slot], NULL, PCTRIE_LOCKED); node->pn_count--; if (node->pn_count > 1) break; for (i = 0; i < PCTRIE_COUNT; i++) { tmp = pctrie_node_load(&node->pn_child[i], NULL, PCTRIE_LOCKED); if (tmp != NULL) break; } KASSERT(i != PCTRIE_COUNT, ("%s: invalid node configuration", __func__)); if (parent == NULL) pctrie_root_store(ptree, tmp, PCTRIE_LOCKED); else { slot = pctrie_slot(index, parent->pn_clev); KASSERT(pctrie_node_load( &parent->pn_child[slot], NULL, PCTRIE_LOCKED) == node, ("%s: invalid child value", __func__)); pctrie_node_store(&parent->pn_child[slot], tmp, PCTRIE_LOCKED); } /* * The child is still valid and we can not zero the * pointer until all SMR references are gone. */ node->pn_count--; pctrie_node_put(ptree, node, freefn, i); break; } parent = node; node = tmp; } } /* * Remove and free all the nodes from the tree. * This function is recursive but there is a tight control on it as the * maximum depth of the tree is fixed. */ void pctrie_reclaim_allnodes(struct pctrie *ptree, pctrie_free_t freefn) { struct pctrie_node *root; root = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); if (root == NULL) return; pctrie_root_store(ptree, NULL, PCTRIE_UNSERIALIZED); if (!pctrie_isleaf(root)) pctrie_reclaim_allnodes_int(ptree, root, freefn); } #ifdef DDB /* * Show details about the given node. */ DB_SHOW_COMMAND(pctrienode, db_show_pctrienode) { struct pctrie_node *node, *tmp; int i; if (!have_addr) return; node = (struct pctrie_node *)addr; db_printf("node %p, owner %jx, children count %u, level %u:\n", (void *)node, (uintmax_t)node->pn_owner, node->pn_count, node->pn_clev); for (i = 0; i < PCTRIE_COUNT; i++) { tmp = pctrie_node_load(&node->pn_child[i], NULL, PCTRIE_UNSERIALIZED); if (tmp != NULL) db_printf("slot: %d, val: %p, value: %p, clev: %d\n", i, (void *)tmp, pctrie_isleaf(tmp) ? pctrie_toval(tmp) : NULL, node->pn_clev); } } #endif /* DDB */
Upload File
Create Folder