From 378df8cf5bfa4d9f3b0f5dc9c7e299d3fc0aa0f6 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Sun, 18 Sep 2022 13:35:09 +0200 Subject: [PATCH] init 2019 --- .gitignore | 1 + 2019/.dir-locals.el | 4 + 2019/.projectile | 0 2019/Makefile | 87 ++++ 2019/RESULTS.txt | 0 2019/day01/INPUT.txt | 100 ++++ 2019/day01/Makefile | 77 +++ 2019/day01/README.org | 43 ++ 2019/day01/aoc-c.c | 115 +++++ 2019/include/bits.h | 296 +++++++++++ 2019/include/bug.h | 70 +++ 2019/include/container-of.h | 30 ++ 2019/include/debug.h | 98 ++++ 2019/include/hash.h | 101 ++++ 2019/include/hashtable.h | 204 ++++++++ 2019/include/likely.h | 18 + 2019/include/list.h | 992 ++++++++++++++++++++++++++++++++++++ 2019/include/plist.h | 301 +++++++++++ 2019/include/pool.h | 90 ++++ 2019/include/rwonce.h | 128 +++++ 2019/libsrc/debug.c | 111 ++++ 2019/libsrc/plist.c | 173 +++++++ 2019/libsrc/pool.c | 222 ++++++++ 23 files changed, 3261 insertions(+) create mode 100644 2019/.dir-locals.el create mode 100644 2019/.projectile create mode 100644 2019/Makefile create mode 100644 2019/RESULTS.txt create mode 100644 2019/day01/INPUT.txt create mode 100644 2019/day01/Makefile create mode 100644 2019/day01/README.org create mode 100644 2019/day01/aoc-c.c create mode 100644 2019/include/bits.h create mode 100644 2019/include/bug.h create mode 100644 2019/include/container-of.h create mode 100644 2019/include/debug.h create mode 100644 2019/include/hash.h create mode 100644 2019/include/hashtable.h create mode 100644 2019/include/likely.h create mode 100644 2019/include/list.h create mode 100644 2019/include/plist.h create mode 100644 2019/include/pool.h create mode 100644 2019/include/rwonce.h create mode 100644 2019/libsrc/debug.c create mode 100644 2019/libsrc/plist.c create mode 100644 2019/libsrc/pool.c diff --git a/.gitignore b/.gitignore index 28c5b9b..1fffb58 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ ex*-c aoc-c core* +.ccls* gmon.out *.o ex*-cob diff --git a/2019/.dir-locals.el b/2019/.dir-locals.el new file mode 100644 index 0000000..a831374 --- /dev/null +++ b/2019/.dir-locals.el @@ -0,0 +1,4 @@ +((nil . ((eval . (let ((root (expand-file-name (projectile-project-root)))) + (setq-local + flycheck-gcc-include-path (list (concat root "include")) + compile-command (concat "make -C " root " all"))))))) diff --git a/2019/.projectile b/2019/.projectile new file mode 100644 index 0000000..e69de29 diff --git a/2019/Makefile b/2019/Makefile new file mode 100644 index 0000000..0f947ba --- /dev/null +++ b/2019/Makefile @@ -0,0 +1,87 @@ +# AOC Makefile - GNU make only. +# +# Copyright (C) 2021 Bruno Raoult ("br") +# Licensed under the GNU General Public License v3.0 or later. +# Some rights reserved. See COPYING. +# +# You should have received a copy of the GNU General Public License along with this +# program. If not, see . +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + + +SUBDIRS := $(shell echo day??) + +CC = gcc + +#LIBS = -lreadline -lncurses +CFLAGS += -std=gnu11 + +CFLAGS += -O2 +CFLAGS += -g +#CFLAGS += -pg +CFLAGS += -Wall +CFLAGS += -Wextra +CFLAGS += -march=native + +CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c) +CFLAGS += -DDEBUG_POOL # memory pools management + +INCDIR := ./include +LIBSRCDIR := ./libsrc +LIBDIR := ./lib +LIB := libaoc_$(shell uname -m) +SLIB := $(LIBDIR)/$(LIB).a +DLIB := $(LIBDIR)/$(LIB).so +LIBSRC := $(wildcard $(LIBSRCDIR)/*.c) +LIBOBJ := $(patsubst %.c,%.o,$(LIBSRC)) +LDFLAGS := -L$(LIBDIR) +LDLIB := -l$(LIB) + +.PHONY: clean cleanlib cleanall all redo output lib $(SUBDIRS) + +all: lib $(SUBDIRS) + +clean: + @for dir in $(SUBDIRS) ; do \ + $(MAKE) --no-print-directory -C $$dir clean ; \ + done + +cleanlib: clean + @$(RM) -f $(SLIB) $(DLIB) $(LIBOBJ) + +cleanall: clean cleanlib + +redo: cleanall all + +$(SUBDIRS): + @echo "=========================================" + @echo "================= $@ =================" + @echo "=========================================" + @echo + @echo "+++++++++++++++++ part 1" + +@$(MAKE) --no-print-directory -C $@ ex1 2>&1 + @echo "+++++++++++++++++ part 2" + +@$(MAKE) --no-print-directory -C $@ ex2 2>&1 + +output: + @$(MAKE) --no-print-directory all >OUTPUT 2>&1 + +lib: $(DLIB) $(SLIB) + +$(SLIB): $(LIBOBJ) + @echo building $@ static library. + @mkdir -p $(LIBDIR) + @$(AR) $(ARFLAGS) -o $@ $^ + +$(DLIB): CFLAGS += -fPIC +$(DLIB): LDFLAGS += -shared +$(DLIB): $(LIBOBJ) + @echo building $@ shared library. + @mkdir -p $(LIBDIR) + @$(CC) $(LDFLAGS) $^ -o $@ + +.c.o: + @echo compiling $<. + @$(CC) -c $(CFLAGS) $(LDFLAGS) -I $(INCDIR) -o $@ $< diff --git a/2019/RESULTS.txt b/2019/RESULTS.txt new file mode 100644 index 0000000..e69de29 diff --git a/2019/day01/INPUT.txt b/2019/day01/INPUT.txt new file mode 100644 index 0000000..8a5a68c --- /dev/null +++ b/2019/day01/INPUT.txt @@ -0,0 +1,100 @@ +123457 +98952 +65241 +62222 +144922 +111868 +71513 +74124 +140122 +133046 +65283 +107447 +144864 +136738 +118458 +91049 +71486 +100320 +143765 +88677 +62034 +139946 +81017 +128668 +126450 +56551 +136839 +64516 +91821 +139909 +52907 +78846 +102008 +58518 +128627 +71256 +133546 +90986 +50808 +139055 +88769 +94491 +128902 +55976 +103658 +123605 +113468 +128398 +61725 +100388 +96763 +101378 +139952 +138298 +87171 +51840 +64828 +58250 +88273 +136781 +120097 +127291 +143752 +117291 +100023 +147239 +71296 +100907 +127612 +122424 +62942 +95445 +74040 +118994 +81810 +146408 +98939 +71359 +112120 +100630 +139576 +98998 +92481 +53510 +76343 +125428 +73447 +62472 +91370 +73506 +126539 +50739 +73133 +81906 +100856 +52758 +142303 +107605 +77797 +124355 diff --git a/2019/day01/Makefile b/2019/day01/Makefile new file mode 100644 index 0000000..08142b9 --- /dev/null +++ b/2019/day01/Makefile @@ -0,0 +1,77 @@ +# AOC daily Makefile - GNU make only. +# +# Copyright (C) 2021 Bruno Raoult ("br") +# Licensed under the GNU General Public License v3.0 or later. +# Some rights reserved. See COPYING. +# +# You should have received a copy of the GNU General Public License along with this +# program. If not, see . +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +INPUT := INPUT.txt +SHELL := /bin/bash + +CC := gcc + +LIB := aoc_$(shell uname -m) +INCDIR := ../include +LIBDIR := ../lib +LDFLAGS := -L$(LIBDIR) +#LDLIB := -l$(LIB) -lm +LDLIB := -l$(LIB) + +export LD_LIBRARY_PATH = $(LIBDIR) + +CFLAGS += -std=gnu99 +CFLAGS += -O2 +CFLAGS += -g +# for gprof +#CFLAGS += -pg +CFLAGS += -Wall +CFLAGS += -Wextra +CFLAGS += -march=native +# Next one may be useful for valgrind (some invalid instructions) +# CFLAGS += -mno-tbm +CFLAGS += -Wmissing-declarations +CFLAGS += -Wno-unused-result + +CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c) +CFLAGS += -DDEBUG_POOL # memory pools management + +TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n" +export PATH := .:$(PATH) + +.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2 + +all: ex1 + +memcheck: memcheck1 + +memcheck1: + @valgrind -q -s --track-origins=yes aoc-c -p 1 < $(INPUT) + +memcheck2: + @valgrind -q -s --track-origins=yes aoc-c -p 2 < $(INPUT) + +compile: aoc-c + +assembly: aoc-c.s + +ex1: aoc-c + @$(TIME) aoc-c -p 1 < $(INPUT) + +ex2: aoc-c + @$(TIME) aoc-c -p 2 < $(INPUT) + +clean: + @rm -f aoc-c core* vgcore* gmon.out aoc-c.s + +.c: + @echo compiling $< + @$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@ + +.c.s: + @echo generating $@ + @$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@ diff --git a/2019/day01/README.org b/2019/day01/README.org new file mode 100644 index 0000000..61c45df --- /dev/null +++ b/2019/day01/README.org @@ -0,0 +1,43 @@ +* --- Day 1: The Tyranny of the Rocket Equation --- + :PROPERTIES: + :CUSTOM_ID: day-1-the-tyranny-of-the-rocket-equation---- + :END: + +Santa has become stranded at the edge of the Solar System while +delivering presents to other planets! To accurately calculate his +position in space, safely align his warp drive, and return to Earth in +time to save Christmas, he needs you to bring him measurements from +/fifty stars/. + +Collect stars by solving puzzles. Two puzzles will be made available on +each day in the Advent calendar; the second puzzle is unlocked when you +complete the first. Each puzzle grants /one star/. Good luck! + +The Elves quickly load you into a spacecraft and prepare to launch. + +At the first Go / No Go poll, every Elf is Go until the Fuel +Counter-Upper. They haven't determined the amount of fuel required yet. + +Fuel required to launch a given /module/ is based on its /mass/. +Specifically, to find the fuel required for a module, take its mass, +divide by three, round down, and subtract 2. + +For example: + +- For a mass of =12=, divide by 3 and round down to get =4=, then + subtract 2 to get =2=. +- For a mass of =14=, dividing by 3 and rounding down still yields =4=, + so the fuel required is also =2=. +- For a mass of =1969=, the fuel required is =654=. +- For a mass of =100756=, the fuel required is =33583=. + +The Fuel Counter-Upper needs to know the total fuel requirement. To find +it, individually calculate the fuel needed for the mass of each module +(your puzzle input), then add together all the fuel values. + +/What is the sum of the fuel requirements/ for all of the modules on +your spacecraft? + +To begin, [[file:1/input][get your puzzle input]]. + +Answer: diff --git a/2019/day01/aoc-c.c b/2019/day01/aoc-c.c new file mode 100644 index 0000000..3cb524c --- /dev/null +++ b/2019/day01/aoc-c.c @@ -0,0 +1,115 @@ +/* aoc-c.c: Advent of Code 2021, day 1 parts 1 & 2 + * + * Copyright (C) 2021 Bruno Raoult ("br") + * Licensed under the GNU General Public License v3.0 or later. + * Some rights reserved. See COPYING. + * + * You should have received a copy of the GNU General Public License along with this + * program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include +#include +#include + +#include "debug.h" +#include "bits.h" +#include "pool.h" + +struct ranges { + u32 val; + struct list_head list; +}; + +LIST_HEAD(list_head); + +int ex1() +{ + u32 count = 0, res = 0, prev, cur; + + while (scanf("%d", &cur) != EOF) { + if (count && cur > prev) + res++; + count++; + prev = cur; + } + return res; +} + +int ex2() +{ + u32 count = 0, res = 0; + u32 val; + pool_t *pool; + struct ranges *input; + struct ranges *list_cur; + + if (!(pool = pool_create("pool", 10, sizeof (struct ranges)))) + return -1; + + while (scanf("%d", &val) != EOF) { + if (!(input = pool_get(pool))) + return -1; + input->val = val; + list_add_tail(&input->list, &list_head); + + if (count > 2) { + u32 loop = 0, v1 = 0, v2 = 0; + struct ranges *first = list_entry(list_head.next, struct ranges, list); + + list_for_each_entry(list_cur, &list_head, list) { + if (loop < 3) + v1 += list_cur->val; + if (loop > 0) + v2 += list_cur->val; + ++loop; + } + list_del(&first->list); + pool_add(pool, first); + if (v2 > v1) + res++; + } + count++; + } + return res; +} + +static int usage(char *prg) +{ + fprintf(stderr, "Usage: %s [-d debug_level] [-p part]\n", prg); + return 1; +} + +int main(int ac, char **av) +{ + int opt; + u32 exercise = 1, res; + + while ((opt = getopt(ac, av, "d:p:")) != -1) { + switch (opt) { + case 'd': + debug_level_set(atoi(optarg)); + break; + case 'p': /* 1 or 2 */ + exercise = atoi(optarg); + break; + default: + return usage(*av); + } + } + + if (optind < ac) + return usage(*av); + + if (exercise == 1) { + res = ex1(); + printf ("%s : res=%d\n", *av, res); + } else { + res = ex2(); + printf ("%s : res=%d\n", *av, res); + } + + exit (0); +} diff --git a/2019/include/bits.h b/2019/include/bits.h new file mode 100644 index 0000000..ef26e7c --- /dev/null +++ b/2019/include/bits.h @@ -0,0 +1,296 @@ +/* bits.h - bits functions. + * + * Copyright (C) 2021-2022 Bruno Raoult ("br") + * Licensed under the GNU General Public License v3.0 or later. + * Some rights reserved. See COPYING. + * + * You should have received a copy of the GNU General Public License along with this + * program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#ifndef BITS_H +#define BITS_H + +#include + +/* next include will define __WORDSIZE: 32 or 64 + */ +#include + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +/* no plan to support 32bits for now... + */ +#if __WORDSIZE != 64 +#error "Only 64 bits word size supported." +#endif + +/* fixed-size types + */ +typedef int64_t s64; +typedef int32_t s32; +typedef int16_t s16; +typedef int8_t s8; + +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +/* convenience types + */ +typedef unsigned long int ulong; +typedef unsigned int uint; +typedef unsigned short ushort; +typedef unsigned char uchar; + +/* char is a special case, as it can be signed or unsigned + */ +typedef signed char schar; + +/* count trailing zeroes : 00101000 -> 3 + * ^^^ + */ +static __always_inline int ctz64(u64 n) +{ +# if __has_builtin(__builtin_ctzl) +# ifdef DEBUG_BITS + log_f(1, "builtin ctzl.\n"); +# endif + return __builtin_ctzl(n); + +# elif __has_builtin(__builtin_clzl) +# ifdef DEBUG_BITS + log_f(1, "builtin clzl.\n"); +# endif + return __WORDSIZE - (__builtin_clzl(n & -n) + 1); + +# else +# ifdef DEBUG_BITS + log_f(1, "emulated.\n"); +# endif + return popcount64((n & −n) − 1); +# endif +} + +static __always_inline int ctz32(u32 n) +{ +# if __has_builtin(__builtin_ctz) +# ifdef DEBUG_BITS + log_f(1, "builtin ctz.\n"); +# endif + return __builtin_ctzl(n); + +# elif __has_builtin(__builtin_clz) +# ifdef DEBUG_BITS + log_f(1, "builtin clz.\n"); +# endif + return __WORDSIZE - (__builtin_clz(n & -n) + 1); + +# else +# ifdef DEBUG_BITS + log_f(1, "emulated.\n"); +# endif + return popcount32((n & −n) − 1); +# endif +} + +/* clz - count leading zeroes : 00101000 -> 2 + * ^^ + */ +static __always_inline int clz64(u64 n) +{ +# if __has_builtin(__builtin_clzl) +# ifdef DEBUG_BITS + log_f(1, "builtin.\n"); +# endif + return __builtin_clzl(n); + +# else +# ifdef DEBUG_BITS + log_f(1, "emulated.\n"); +# endif + u64 r, q; + + r = (n > 0xFFFFFFFF) << 5; n >>= r; + q = (n > 0xFFFF) << 4; n >>= q; r |= q; + q = (n > 0xFF ) << 3; n >>= q; r |= q; + q = (n > 0xF ) << 2; n >>= q; r |= q; + q = (n > 0x3 ) << 1; n >>= q; r |= q; + r |= (n >> 1); + return 64 - r - 1; +# endif +} + +static __always_inline int clz32(u32 n) +{ +# if __has_builtin(__builtin_clz) +# ifdef DEBUG_BITS + log_f(1, "builtin.\n"); +# endif + return __builtin_clz(n); + +# else +# ifdef DEBUG_BITS + log_f(1, "emulated.\n"); +# endif + u32 r, q; + + r = (n > 0xFFFF) << 4; n >>= r; + q = (n > 0xFF ) << 3; n >>= q; r |= q; + q = (n > 0xF ) << 2; n >>= q; r |= q; + q = (n > 0x3 ) << 1; n >>= q; r |= q; + r |= (n >> 1); + return 32 - r - 1; +# endif +} + +/* fls - find last set : 00101000 -> 6 + * ^ + */ +static __always_inline int fls64(u64 n) +{ + if (!n) + return 0; + return 64 - clz64(n); +} + +static __always_inline int fls32(u32 n) +{ + if (!n) + return 0; + return 32 - clz32(n); +} + +/* find first set : 00101000 -> 4 + * ^ + */ +static __always_inline uint ffs64(u64 n) +{ +# if __has_builtin(__builtin_ffsl) +# ifdef DEBUG_BITS + log_f(1, "builtin ffsl.\n"); +# endif + return __builtin_ffsl(n); + +# elif __has_builtin(__builtin_ctzl) +# ifdef DEBUG_BITS + log_f(1, "builtin ctzl.\n"); +# endif + if (n == 0) + return (0); + return __builtin_ctzl(n) + 1; + +# else +# ifdef DEBUG_BITS + log_f(1, "emulated.\n"); +# endif + return popcount64(n ^ ~-n); +# endif +} + +static __always_inline uint ffs32(u32 n) +{ +# if __has_builtin(__builtin_ffs) +# ifdef DEBUG_BITS + log_f(1, "builtin ffs.\n"); +# endif + return __builtin_ffs(n); + +# elif __has_builtin(__builtin_ctz) +# ifdef DEBUG_BITS + log_f(1, "builtin ctz.\n"); +# endif + if (n == 0) + return (0); + return __builtin_ctz(n) + 1; + +# else +# ifdef DEBUG_BITS + log_f(1, "emulated.\n"); +# endif + return popcount32(n ^ ~-n); +# endif +} + +/* count set bits: 10101000 -> 3 + * ^ ^ ^ + */ +static __always_inline int popcount64(u64 n) +{ +# if __has_builtin(__builtin_popcountl) +# ifdef DEBUG_BITS + log_f(1, "builtin.\n"); +# endif + return __builtin_popcountl(n); + +# else +# ifdef DEBUG_BITS + log_f(1, "emulated.\n"); +# endif + int count = 0; + while (n) { + count++; + n &= (n - 1); + } + return count; +# endif +} + +static __always_inline int popcount32(u32 n) +{ +# if __has_builtin(__builtin_popcount) +# ifdef DEBUG_BITS + log_f(1, "builtin.\n"); +# endif + return __builtin_popcount(n); + +# else +# ifdef DEBUG_BITS + log_f(1, "emulated.\n"); +# endif + int count = 0; + while (n) { + count++; + n &= (n - 1); + } + return count; +# endif +} + + + +/** bit_for_each - iterate over an u64/u32 bits + * @pos: an int used as current bit + * @tmp: a temp u64/u32 used as temporary storage + * @ul: the u64/u32 to loop over + * + * Usage: + * u64 u=139, _t; // u=b10001011 + * int cur; + * bit_for_each64(cur, _t, u) { + * printf("%d\n", cur); + * } + * This will display the position of each bit set in ul: 1, 2, 4, 8 + * + * I should probably re-think the implementation... + */ +#define bit_for_each64(pos, tmp, ul) \ + for (tmp = ul, pos = ffs64(tmp); tmp; tmp &= (tmp - 1), pos = ffs64(tmp)) + +#define bit_for_each32(pos, tmp, ul) \ + for (tmp = ul, pos = ffs32(tmp); tmp; tmp &= (tmp - 1), pos = ffs32(tmp)) + +/** or would it be more useful (counting bits from zero instead of 1) ? + */ +#define bit_for_each64_2(pos, tmp, ul) \ + for (tmp = ul, pos = ctz64(tmp); tmp; tmp ^= 1UL << pos, pos = ctz64(tmp)) + +#define bit_for_each32_2(pos, tmp, ul) \ + for (tmp = ul, pos = ctz32(tmp); tmp; tmp ^= 1U << pos, pos = ctz32(tmp)) + +#endif /* BITS_H */ diff --git a/2019/include/bug.h b/2019/include/bug.h new file mode 100644 index 0000000..2c4566f --- /dev/null +++ b/2019/include/bug.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _BR_BUG_H +#define _BR_BUG_H + +#include +#include +#include +#include "likely.h" +#include "debug.h" + +/* inspired by Linux kernel's */ + +#define panic() exit(0xff) + +/* + * Don't use BUG() or BUG_ON() unless there's really no way out; one + * example might be detecting data structure corruption in the middle + * of an operation that can't be backed out of. If the (sub)system + * can somehow continue operating, perhaps with reduced functionality, + * it's probably not BUG-worthy. + * + * If you're tempted to BUG(), think again: is completely giving up + * really the *only* solution? There are usually better options, where + * users don't need to reboot ASAP and can mostly shut down cleanly. + */ +#define BUG() do { \ + fprintf(stderr, "BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ + panic(); \ + } while (0) + +#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0) + +/* + * WARN(), WARN_ON(), WARN_ON_ONCE, and so on can be used to report + * significant kernel issues that need prompt attention if they should ever + * appear at runtime. + * + * Do not use these macros when checking for invalid external inputs + * (e.g. invalid system call arguments, or invalid data coming from + * network/devices), and on transient conditions like ENOMEM or EAGAIN. + * These macros should be used for recoverable kernel issues only. + * For invalid external inputs, transient conditions, etc use + * pr_err[_once/_ratelimited]() followed by dump_stack(), if necessary. + * Do not include "BUG"/"WARNING" in format strings manually to make these + * conditions distinguishable from kernel issues. + * + * Use the versions with printk format strings to provide better diagnostics. + */ +#define __WARN() do { \ + fprintf(stderr, "WARNING: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ + } while (0) +#define __WARN_printf(arg...) do { \ + vfprintf(stderr, arg); \ + } while (0) + +#define WARN_ON(condition) ({ \ + int __ret_warn_on = !!(condition); \ + if (unlikely(__ret_warn_on)) \ + __WARN(); \ + unlikely(__ret_warn_on); \ + }) + +#define WARN(condition, format...) ({ \ + int __ret_warn_on = !!(condition); \ + if (unlikely(__ret_warn_on)) \ + __WARN_printf(format); \ + unlikely(__ret_warn_on); \ + }) + +#endif /* _BR_BUG_H */ diff --git a/2019/include/container-of.h b/2019/include/container-of.h new file mode 100644 index 0000000..1c7f54f --- /dev/null +++ b/2019/include/container-of.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* adaptation of Linux kernel's + */ +#ifndef _BR_CONTAINER_OF_H +#define _BR_CONTAINER_OF_H + +/* Are two types/vars the same type (ignoring qualifiers)? */ +#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) + +/** + * typeof_member - + */ +#define typeof_member(T, m) typeof(((T*)0)->m) + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + void *__mptr = (void *)(ptr); \ + _Static_assert(__same_type(*(ptr), ((type *)0)->member) || \ + __same_type(*(ptr), void), \ + "pointer type mismatch in container_of()"); \ + ((type *)(__mptr - offsetof(type, member))); }) + +#endif /* BR_CONTAINER_OF_H */ diff --git a/2019/include/debug.h b/2019/include/debug.h new file mode 100644 index 0000000..fcceefd --- /dev/null +++ b/2019/include/debug.h @@ -0,0 +1,98 @@ +/* debug.h - debug/log management. + * + * Copyright (C) 2021-2022 Bruno Raoult ("br") + * Licensed under the GNU General Public License v3.0 or later. + * Some rights reserved. See COPYING. + * + * You should have received a copy of the GNU General Public License along with this + * program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef DEBUG_H +#define DEBUG_H + +#include +#include + +#include "bits.h" + +#define _unused __attribute__((__unused__)) +#define _printf __attribute__ ((format (printf, 6, 7))) + +#ifdef DEBUG_DEBUG +void debug_init(u32 level); +void debug_level_set(u32 level); +void _printf debug(u32 level, bool timestamp, + u32 indent, const char *src, + u32 line, const char *, ...); +#else /* DEBUG_DEBUG */ +static inline void debug_init(_unused u32 level) {} +static inline void debug_level_set(_unused u32 level) {} +static inline void _printf debug(_unused u32 level, _unused bool timestamp, + _unused u32 indent, _unused const char *src, + _unused u32 line, const char *, ...) {} +#endif /* DEBUG_DEBUG */ +#undef _unused +#undef _printf + +/** + * log - simple log (no function name, no indent, no timestamp) + * @level: log level + * @fmt: printf format string + * @args: subsequent arguments to printf + */ +#define log(level, fmt, args...) \ + debug((level), false, 0, NULL, 0, fmt, ##args) + +/** + * log_i - log with indent (no function name, no timestamp) + * @level: log level + * @fmt: printf format string + * @args: subsequent arguments to printf + * + * Output example: + * >>>>val=2 + */ +#define log_i(level, fmt, args...) \ + debug((level), false, (level), NULL, 0, fmt, ##args) + +/** + * log_f - log with function name (no indent name, no timestamp) + * @level: log level + * @fmt: printf format string + * @args: subsequent arguments to printf + * + * Output example: + * [function] val=2 + */ +#define log_f(level, fmt, args...) \ + debug((level), false, 0, __func__, 0, fmt, ##args) + +/** + * log_if - log with function name and line number (no indent name, no timestamp) + * @level: log level + * @fmt: printf format string + * @args: subsequent arguments to printf + * + * Output example: + * >>>> [function:15] val=2 + */ +#define log_if(level, fmt, args...) \ + debug((level), false, (level), __func__, __LINE__, fmt, ##args) + +/** + * log_it - log with function name, line number, indent, and timestamp + * @level: log level + * @fmt: printf format string + * @args: subsequent arguments to printf + * + * Output example: + * >>>> [function:15] val=2 + */ +#define log_it(level, fmt, args...) \ + debug((level), true, (level), __func__, __LINE__, fmt, ##args) + +#endif /* DEBUG_H */ diff --git a/2019/include/hash.h b/2019/include/hash.h new file mode 100644 index 0000000..5ce4330 --- /dev/null +++ b/2019/include/hash.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _BR_HASH_H +#define _BR_HASH_H +/* adaptation of Linux kernel's + */ + +/* Fast hashing routine for ints, longs and pointers. + (C) 2002 Nadia Yvette Chambers, IBM */ + +#include +#include +#include "bits.h" +/* + * The "GOLDEN_RATIO_PRIME" is used in ifs/btrfs/brtfs_inode.h and + * fs/inode.c. It's not actually prime any more (the previous primes + * were actively bad for hashing), but the name remains. + */ +#if __BITS_PER_LONG == 32 +#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_32 +#define hash_long(val, bits) hash_32(val, bits) +#elif __BITS_PER_LONG == 64 +#define hash_long(val, bits) hash_64(val, bits) +#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_64 +#else +#error Wordsize not 32 or 64 +#endif + +/* + * This hash multiplies the input by a large odd number and takes the + * high bits. Since multiplication propagates changes to the most + * significant end only, it is essential that the high bits of the + * product be used for the hash value. + * + * Chuck Lever verified the effectiveness of this technique: + * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf + * + * Although a random odd number will do, it turns out that the golden + * ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice + * properties. (See Knuth vol 3, section 6.4, exercise 9.) + * + * These are the negative, (1 - phi) = phi**2 = (3 - sqrt(5))/2, + * which is very slightly easier to multiply by and makes no + * difference to the hash distribution. + */ +#define GOLDEN_RATIO_32 0x61C88647 +#define GOLDEN_RATIO_64 0x61C8864680B583EBull + +/* + * The _generic versions exist only so lib/test_hash.c can compare + * the arch-optimized versions with the generic. + * + * Note that if you change these, any that aren't updated + * to match need to have their HAVE_ARCH_* define values updated so the + * self-test will not false-positive. + */ +#ifndef HAVE_ARCH__HASH_32 +#define __hash_32 __hash_32_generic +#endif +static inline u32 __hash_32_generic(u32 val) +{ + return val * GOLDEN_RATIO_32; +} + +static inline u32 hash_32(u32 val, unsigned int bits) +{ + /* High bits are more random, so use them. */ + return __hash_32(val) >> (32 - bits); +} + +#ifndef HAVE_ARCH_HASH_64 +#define hash_64 hash_64_generic +#endif +static __always_inline u32 hash_64_generic(u64 val, unsigned int bits) +{ +#if __BITS_PER_LONG == 64 + /* 64x64-bit multiply is efficient on all 64-bit processors */ + return val * GOLDEN_RATIO_64 >> (64 - bits); +#else + /* Hash 64 bits using only 32x32-bit multiply. */ + return hash_32((u32)val ^ __hash_32(val >> 32), bits); +#endif +} + +static inline u32 hash_ptr(const void *ptr, unsigned int bits) +{ + return hash_long((unsigned long)ptr, bits); +} + +/* This really should be called fold32_ptr; it does no hashing to speak of. */ +static inline u32 hash32_ptr(const void *ptr) +{ + unsigned long val = (unsigned long)ptr; + +#if __BITS_PER_LONG == 64 + val ^= (val >> 32); +#endif + return (u32)val; +} + +#endif /* _BR_HASH_H */ diff --git a/2019/include/hashtable.h b/2019/include/hashtable.h new file mode 100644 index 0000000..9393583 --- /dev/null +++ b/2019/include/hashtable.h @@ -0,0 +1,204 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* adaptation of Linux kernel's + */ + + +/* + * Statically sized hash table implementation + * (C) 2012 Sasha Levin + */ + +#ifndef _LINUX_HASHTABLE_H +#define _LINUX_HASHTABLE_H + +#include "list.h" +#include +#include +#include "hash.h" +//#include + +#define DEFINE_HASHTABLE(name, bits) \ + struct hlist_head name[1 << (bits)] = \ + { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } + +#define DEFINE_READ_MOSTLY_HASHTABLE(name, bits) \ + struct hlist_head name[1 << (bits)] __read_mostly = \ + { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } + +#define DECLARE_HASHTABLE(name, bits) \ + struct hlist_head name[1 << (bits)] + +#define HASH_SIZE(name) (ARRAY_SIZE(name)) +#define HASH_BITS(name) ilog2(HASH_SIZE(name)) + +/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */ +#define hash_min(val, bits) \ + (sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits)) + +static inline void __hash_init(struct hlist_head *ht, unsigned int sz) +{ + unsigned int i; + + for (i = 0; i < sz; i++) + INIT_HLIST_HEAD(&ht[i]); +} + +/** + * hash_init - initialize a hash table + * @hashtable: hashtable to be initialized + * + * Calculates the size of the hashtable from the given parameter, otherwise + * same as hash_init_size. + * + * This has to be a macro since HASH_BITS() will not work on pointers since + * it calculates the size during preprocessing. + */ +#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable)) + +/** + * hash_add - add an object to a hashtable + * @hashtable: hashtable to add to + * @node: the &struct hlist_node of the object to be added + * @key: the key of the object to be added + */ +#define hash_add(hashtable, node, key) \ + hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))]) + +/** + * hash_add_rcu - add an object to a rcu enabled hashtable + * @hashtable: hashtable to add to + * @node: the &struct hlist_node of the object to be added + * @key: the key of the object to be added + */ +#define hash_add_rcu(hashtable, node, key) \ + hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))]) + +/** + * hash_hashed - check whether an object is in any hashtable + * @node: the &struct hlist_node of the object to be checked + */ +static inline bool hash_hashed(struct hlist_node *node) +{ + return !hlist_unhashed(node); +} + +static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz) +{ + unsigned int i; + + for (i = 0; i < sz; i++) + if (!hlist_empty(&ht[i])) + return false; + + return true; +} + +/** + * hash_empty - check whether a hashtable is empty + * @hashtable: hashtable to check + * + * This has to be a macro since HASH_BITS() will not work on pointers since + * it calculates the size during preprocessing. + */ +#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable)) + +/** + * hash_del - remove an object from a hashtable + * @node: &struct hlist_node of the object to remove + */ +static inline void hash_del(struct hlist_node *node) +{ + hlist_del_init(node); +} + +/** + * hash_for_each - iterate over a hashtable + * @name: hashtable to iterate + * @bkt: integer to use as bucket loop cursor + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + */ +#define hash_for_each(name, bkt, obj, member) \ + for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ + (bkt)++)\ + hlist_for_each_entry(obj, &name[bkt], member) + +/** + * hash_for_each_rcu - iterate over a rcu enabled hashtable + * @name: hashtable to iterate + * @bkt: integer to use as bucket loop cursor + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + */ +#define hash_for_each_rcu(name, bkt, obj, member) \ + for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ + (bkt)++)\ + hlist_for_each_entry_rcu(obj, &name[bkt], member) + +/** + * hash_for_each_safe - iterate over a hashtable safe against removal of + * hash entry + * @name: hashtable to iterate + * @bkt: integer to use as bucket loop cursor + * @tmp: a &struct hlist_node used for temporary storage + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + */ +#define hash_for_each_safe(name, bkt, tmp, obj, member) \ + for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ + (bkt)++)\ + hlist_for_each_entry_safe(obj, tmp, &name[bkt], member) + +/** + * hash_for_each_possible - iterate over all possible objects hashing to the + * same bucket + * @name: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + * @key: the key of the objects to iterate over + */ +#define hash_for_each_possible(name, obj, member, key) \ + hlist_for_each_entry(obj, &name[hash_min(key, HASH_BITS(name))], member) + +/** + * hash_for_each_possible_rcu - iterate over all possible objects hashing to the + * same bucket in an rcu enabled hashtable + * @name: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + * @key: the key of the objects to iterate over + */ +#define hash_for_each_possible_rcu(name, obj, member, key, cond...) \ + hlist_for_each_entry_rcu(obj, &name[hash_min(key, HASH_BITS(name))],\ + member, ## cond) + +/** + * hash_for_each_possible_rcu_notrace - iterate over all possible objects hashing + * to the same bucket in an rcu enabled hashtable in a rcu enabled hashtable + * @name: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + * @key: the key of the objects to iterate over + * + * This is the same as hash_for_each_possible_rcu() except that it does + * not do any RCU debugging or tracing. + */ +#define hash_for_each_possible_rcu_notrace(name, obj, member, key) \ + hlist_for_each_entry_rcu_notrace(obj, \ + &name[hash_min(key, HASH_BITS(name))], member) + +/** + * hash_for_each_possible_safe - iterate over all possible objects hashing to the + * same bucket safe against removals + * @name: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @tmp: a &struct hlist_node used for temporary storage + * @member: the name of the hlist_node within the struct + * @key: the key of the objects to iterate over + */ +#define hash_for_each_possible_safe(name, obj, tmp, member, key) \ + hlist_for_each_entry_safe(obj, tmp,\ + &name[hash_min(key, HASH_BITS(name))], member) + + +#endif diff --git a/2019/include/likely.h b/2019/include/likely.h new file mode 100644 index 0000000..a5d151d --- /dev/null +++ b/2019/include/likely.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* taken from Kernel's + * + */ + +#ifndef __BR_LIST_H +#define __BR_LIST_H + +#include +#include +#include "rwonce.h" +#include "container-of.h" + +/************ originally in */ +struct list_head { + struct list_head *next, *prev; +}; +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +/************ originally in */ +# define POISON_POINTER_DELTA 0 +/* These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x100 + POISON_POINTER_DELTA) +#define LIST_POISON2 ((void *) 0x200 + POISON_POINTER_DELTA) + +/* + * Circular doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +/** + * INIT_LIST_HEAD - Initialize a list_head structure + * @list: list_head structure to be initialized. + * + * Initializes the list_head to point to itself. If it is a list header, + * the result is an empty list. + */ +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + WRITE_ONCE(list->next, list); + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + WRITE_ONCE(prev->next, new); +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + WRITE_ONCE(prev->next, next); +} + +/* + * Delete a list entry and clear the 'prev' pointer. + * + * This is a special-purpose list clearing method used in the networking code + * for lists allocated as per-cpu, where we don't want to incur the extra + * WRITE_ONCE() overhead of a regular list_del_init(). The code that uses this + * needs to check the node 'prev' pointer instead of calling list_empty(). + */ +static inline void __list_del_clearprev(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->prev = NULL; +} + +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del_entry(entry); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +/** + * list_replace_init - replace old entry by new one and initialize the old one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_swap - replace entry1 with entry2 and re-add entry1 at entry2's position + * @entry1: the location to place entry2 + * @entry2: the location to place entry1 + */ +static inline void list_swap(struct list_head *entry1, + struct list_head *entry2) +{ + struct list_head *pos = entry2->prev; + + list_del(entry2); + list_replace(entry1, entry2); + if (pos == entry1) + pos = entry2; + list_add(entry1, pos); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del_entry(entry); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del_entry(list); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del_entry(list); + list_add_tail(list, head); +} + +/** + * list_bulk_move_tail - move a subsection of a list to its tail + * @head: the head that will follow our entry + * @first: first entry to move + * @last: last entry to move, can be the same as first + * + * Move all entries between @first and including @last before @head. + * All three entries must belong to the same linked list. + */ +static inline void list_bulk_move_tail(struct list_head *head, + struct list_head *first, + struct list_head *last) +{ + first->prev->next = last->next; + last->next->prev = first->prev; + + head->prev->next = first; + first->prev = head->prev; + + last->next = head; + head->prev = last; +} + +/** + * list_is_first -- tests whether @list is the first entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_first(const struct list_head *list, + const struct list_head *head) +{ + return list->prev == head; +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return READ_ONCE(head->next) == head; +} + +/** + * list_rotate_left - rotate the list to the left + * @head: the head of the list + */ +static inline void list_rotate_left(struct list_head *head) +{ + struct list_head *first; + + if (!list_empty(head)) { + first = head->next; + list_move_tail(first, head); + } +} + +/** + * list_rotate_to_front() - Rotate list to specific item. + * @list: The desired new front of the list. + * @head: The head of the list. + * + * Rotates list so that @list becomes the new front of the list. + */ +static inline void list_rotate_to_front(struct list_head *list, + struct list_head *head) +{ + /* + * Deletes the list head from the list denoted by @head and + * places it as the tail of @list, this effectively rotates the + * list so that @list is at the front. + */ + list_move_tail(head, list); +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +static inline void __list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + struct list_head *new_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; +} + +/** + * list_cut_position - cut a list into two + * @list: a new list to add all removed entries + * @head: a list with entries + * @entry: an entry within head, could be the head itself + * and if so we won't cut the list + * + * This helper moves the initial part of @head, up to and + * including @entry, from @head to @list. You should + * pass on @entry an element you know is on @head. @list + * should be an empty list or a list you do not care about + * losing its data. + * + */ +static inline void list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + if (list_empty(head)) + return; + if (list_is_singular(head) && + (head->next != entry && head != entry)) + return; + if (entry == head) + INIT_LIST_HEAD(list); + else + __list_cut_position(list, head, entry); +} + +/** + * list_cut_before - cut a list into two, before given entry + * @list: a new list to add all removed entries + * @head: a list with entries + * @entry: an entry within head, could be the head itself + * + * This helper moves the initial part of @head, up to but + * excluding @entry, from @head to @list. You should pass + * in @entry an element you know is on @head. @list should + * be an empty list or a list you do not care about losing + * its data. + * If @entry == @head, all entries on @head are moved to + * @list. + */ +static inline void list_cut_before(struct list_head *list, + struct list_head *head, + struct list_head *entry) +{ + if (head->next == entry) { + INIT_LIST_HEAD(list); + return; + } + list->next = head->next; + list->next->prev = list; + list->prev = entry->prev; + list->prev->next = list; + head->next = entry; + entry->prev = head; +} + +static inline void __list_splice(const struct list_head *list, + struct list_head *prev, + struct list_head *next) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** + * list_splice - join two lists, this is designed for stacks + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(const struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head, head->next); +} + +/** + * list_splice_tail - join two lists, each list being a queue + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head->prev, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head, head->next); + INIT_LIST_HEAD(list); + } +} + +/** + * list_splice_tail_init - join two lists and reinitialise the emptied list + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +static inline void list_splice_tail_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_last_entry - get the last element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +/** + * list_first_entry_or_null - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note that if the list is empty, it returns NULL. + */ +#define list_first_entry_or_null(ptr, type, member) ({ \ + struct list_head *head__ = (ptr); \ + struct list_head *pos__ = READ_ONCE(head__->next); \ + pos__ != head__ ? list_entry(pos__, type, member) : NULL; \ + }) + +/** + * list_next_entry - get the next element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, __typeof__(*(pos)), member) + +/** + * list_prev_entry - get the prev element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_prev_entry(pos, member) \ + list_entry((pos)->member.prev, __typeof__(*(pos)), member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_continue - continue iteration over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * Continue to iterate over a list, continuing after the current position. + */ +#define list_for_each_continue(pos, head) \ + for (pos = pos->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + pos != (head); \ + pos = n, n = pos->prev) + +/** + * list_entry_is_head - test if the entry points to the head of the list + * @pos: the type * to cursor + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_entry_is_head(pos, head, member) \ + (&pos->member == (head)) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, __typeof__(*pos), member); \ + !list_entry_is_head(pos, head, member); \ + pos = list_next_entry(pos, member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_last_entry(head, __typeof__(*pos), member); \ + !list_entry_is_head(pos, head, member); \ + pos = list_prev_entry(pos, member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_head within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, __typeof__(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_next_entry(pos, member); \ + !list_entry_is_head(pos, head, member); \ + pos = list_next_entry(pos, member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_prev_entry(pos, member); \ + !list_entry_is_head(pos, head, member); \ + pos = list_prev_entry(pos, member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; !list_entry_is_head(pos, head, member); \ + pos = list_next_entry(pos, member)) + +/** + * list_for_each_entry_from_reverse - iterate backwards over list of given type + * from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate backwards over list of given type, continuing from current position. + */ +#define list_for_each_entry_from_reverse(pos, head, member) \ + for (; !list_entry_is_head(pos, head, member); \ + pos = list_prev_entry(pos, member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_first_entry(head, __typeof__(*pos), member), \ + n = list_next_entry(pos, member); \ + !list_entry_is_head(pos, head, member); \ + pos = n, n = list_next_entry(n, member)) + +/** + * list_for_each_entry_safe_continue - continue list iteration safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_next_entry(pos, member), \ + n = list_next_entry(pos, member); \ + !list_entry_is_head(pos, head, member); \ + pos = n, n = list_next_entry(n, member)) + +/** + * list_for_each_entry_safe_from - iterate over list from current point safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_next_entry(pos, member); \ + !list_entry_is_head(pos, head, member); \ + pos = n, n = list_next_entry(n, member)) + +/** + * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_last_entry(head, __typeof__(*pos), member), \ + n = list_prev_entry(pos, member); \ + !list_entry_is_head(pos, head, member); \ + pos = n, n = list_prev_entry(n, member)) + +/** + * list_safe_reset_next - reset a stale list_for_each_entry_safe loop + * @pos: the loop cursor used in the list_for_each_entry_safe loop + * @n: temporary storage used in list_for_each_entry_safe + * @member: the name of the list_head within the struct. + * + * list_safe_reset_next is not safe to use in general if the list may be + * modified concurrently (eg. the lock is dropped in the loop body). An + * exception to this is if the cursor element (pos) is pinned in the list, + * and list_safe_reset_next is called after re-taking the lock and before + * completing the current iteration of the loop body. + */ +#define list_safe_reset_next(pos, n, member) \ + n = list_next_entry(pos, member) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE(struct hlist_node *h) +{ + h->next = NULL; + h->pprev = NULL; +} + +/** + * hlist_unhashed - Has node been removed from list and reinitialized? + * @h: Node to be checked + * + * Not that not all removal functions will leave a node in unhashed + * state. For example, hlist_nulls_del_init_rcu() does leave the + * node in unhashed state, but hlist_nulls_del() does not. + */ +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +/** + * hlist_unhashed_lockless - Version of hlist_unhashed for lockless use + * @h: Node to be checked + * + * This variant of hlist_unhashed() must be used in lockless contexts + * to avoid potential load-tearing. The READ_ONCE() is paired with the + * various WRITE_ONCE() in hlist helpers that are defined below. + */ +static inline int hlist_unhashed_lockless(const struct hlist_node *h) +{ + return !READ_ONCE(h->pprev); +} + +/** + * hlist_empty - Is the specified hlist_head structure an empty hlist? + * @h: Structure to check. + */ +static inline int hlist_empty(const struct hlist_head *h) +{ + return !READ_ONCE(h->first); +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + + WRITE_ONCE(*pprev, next); + if (next) + WRITE_ONCE(next->pprev, pprev); +} + +/** + * hlist_del - Delete the specified hlist_node from its list + * @n: Node to delete. + * + * Note that this function leaves the node in hashed state. Use + * hlist_del_init() or similar instead to unhash @n. + */ +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +/** + * hlist_del_init - Delete the specified hlist_node from its list and initialize + * @n: Node to delete. + * + * Note that this function leaves the node in unhashed state. + */ +static inline void hlist_del_init(struct hlist_node *n) +{ + if (!hlist_unhashed(n)) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +/** + * hlist_add_head - add a new entry at the beginning of the hlist + * @n: new entry to be added + * @h: hlist head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + WRITE_ONCE(n->next, first); + if (first) + WRITE_ONCE(first->pprev, &n->next); + WRITE_ONCE(h->first, n); + WRITE_ONCE(n->pprev, &h->first); +} + +/** + * hlist_add_before - add a new entry before the one specified + * @n: new entry to be added + * @next: hlist node to add it before, which must be non-NULL + */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + WRITE_ONCE(n->pprev, next->pprev); + WRITE_ONCE(n->next, next); + WRITE_ONCE(next->pprev, &n->next); + WRITE_ONCE(*(n->pprev), n); +} + +/** + * hlist_add_behind - add a new entry after the one specified + * @n: new entry to be added + * @prev: hlist node to add it after, which must be non-NULL + */ +static inline void hlist_add_behind(struct hlist_node *n, + struct hlist_node *prev) +{ + WRITE_ONCE(n->next, prev->next); + WRITE_ONCE(prev->next, n); + WRITE_ONCE(n->pprev, &prev->next); + + if (n->next) + WRITE_ONCE(n->next->pprev, &n->next); +} + +/** + * hlist_add_fake - create a fake hlist consisting of a single headless node + * @n: Node to make a fake list out of + * + * This makes @n appear to be its own predecessor on a headless hlist. + * The point of this is to allow things like hlist_del() to work correctly + * in cases where there is no list. + */ +static inline void hlist_add_fake(struct hlist_node *n) +{ + n->pprev = &n->next; +} + +/** + * hlist_fake: Is this node a fake hlist? + * @h: Node to check for being a self-referential fake hlist. + */ +static inline bool hlist_fake(struct hlist_node *h) +{ + return h->pprev == &h->next; +} + +/** + * hlist_is_singular_node - is node the only element of the specified hlist? + * @n: Node to check for singularity. + * @h: Header for potentially singular list. + * + * Check whether the node is the only node of the head without + * accessing head, thus avoiding unnecessary cache misses. + */ +static inline bool +hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h) +{ + return !n->next && n->pprev == &h->first; +} + +/** + * hlist_move_list - Move an hlist + * @old: hlist_head for old list. + * @new: hlist_head for new list. + * + * Move a list from one list head to another. Fixup the pprev + * reference of the first entry if it exists. + */ +static inline void hlist_move_list(struct hlist_head *old, + struct hlist_head *new) +{ + new->first = old->first; + if (new->first) + new->first->pprev = &new->first; + old->first = NULL; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos ; pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +#define hlist_entry_safe(ptr, type, member) \ + ({ __typeof__(ptr) ____ptr = (ptr); \ + ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ + }) + +/** + * hlist_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(pos, head, member) \ + for (pos = hlist_entry_safe((head)->first, __typeof__(*(pos)), member); \ + pos; \ + pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member)) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after current point + * @pos: the type * to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(pos, member) \ + for (pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member); \ + pos; \ + pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member)) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from current point + * @pos: the type * to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(pos, member) \ + for (; pos; \ + pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member)) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: a &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(pos, n, head, member) \ + for (pos = hlist_entry_safe((head)->first, __typeof__(*pos), member); \ + pos && ({ n = pos->member.next; 1; }); \ + pos = hlist_entry_safe(n, __typeof__(*pos), member)) + +#endif /* __BR_LIST_H */ diff --git a/2019/include/plist.h b/2019/include/plist.h new file mode 100644 index 0000000..df0e88a --- /dev/null +++ b/2019/include/plist.h @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Descending-priority-sorted double-linked list + * + * (C) 2002-2003 Intel Corp + * Inaky Perez-Gonzalez . + * + * 2001-2005 (c) MontaVista Software, Inc. + * Daniel Walker + * + * (C) 2005 Thomas Gleixner + * + * Simplifications of the original code by + * Oleg Nesterov + * + * Based on simple lists (include/linux/list.h). + * + * This is a priority-sorted list of nodes; each node has a + * priority from INT_MIN (highest) to INT_MAX (lowest). + * + * Addition is O(K), removal is O(1), change of priority of a node is + * O(K) and K is the number of RT priority levels used in the system. + * (1 <= K <= 99) + * + * This list is really a list of lists: + * + * - The tier 1 list is the prio_list, different priority nodes. + * + * - The tier 2 list is the node_list, serialized nodes. + * + * Simple ASCII art explanation: + * + * pl:prio_list (only for plist_node) + * nl:node_list + * HEAD| NODE(S) + * | + * ||------------------------------------| + * ||->|pl|<->|pl|<--------------->|pl|<-| + * | |10| |21| |21| |21| |40| (prio) + * | | | | | | | | | | | + * | | | | | | | | | | | + * |->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-| + * |-------------------------------------------| + * + * The nodes on the prio_list list are sorted by priority to simplify + * the insertion of new nodes. There are no nodes with duplicate + * priorites on the list. + * + * The nodes on the node_list are ordered by priority and can contain + * entries which have the same priority. Those entries are ordered + * FIFO + * + * Addition means: look for the prio_list node in the prio_list + * for the priority of the node and insert it before the node_list + * entry of the next prio_list node. If it is the first node of + * that priority, add it to the prio_list in the right position and + * insert it into the serialized node_list list + * + * Removal means remove it from the node_list and remove it from + * the prio_list if the node_list list_head is non empty. In case + * of removal from the prio_list it must be checked whether other + * entries of the same priority are on the list or not. If there + * is another entry of the same priority then this entry has to + * replace the removed entry on the prio_list. If the entry which + * is removed is the only entry of this priority then a simple + * remove from both list is sufficient. + * + * INT_MIN is the highest priority, 0 is the medium highest, INT_MAX + * is lowest priority. + * + * No locking is done, up to the caller. + */ +#ifndef _LINUX_PLIST_H_ +#define _LINUX_PLIST_H_ + +#include "container-of.h" +#include "list.h" +//#include + +// #include + +struct plist_head { + struct list_head node_list; +}; + +struct plist_node { + int prio; + struct list_head prio_list; + struct list_head node_list; +}; + +/** + * PLIST_HEAD_INIT - static struct plist_head initializer + * @head: struct plist_head variable name + */ +#define PLIST_HEAD_INIT(head) \ + { \ + .node_list = LIST_HEAD_INIT((head).node_list) \ + } + +/** + * PLIST_HEAD - declare and init plist_head + * @head: name for struct plist_head variable + */ +#define PLIST_HEAD(head) \ + struct plist_head head = PLIST_HEAD_INIT(head) + +/** + * PLIST_NODE_INIT - static struct plist_node initializer + * @node: struct plist_node variable name + * @__prio: initial node priority + */ +#define PLIST_NODE_INIT(node, __prio) \ + { \ + .prio = (__prio), \ + .prio_list = LIST_HEAD_INIT((node).prio_list), \ + .node_list = LIST_HEAD_INIT((node).node_list), \ + } + +/** + * plist_head_init - dynamic struct plist_head initializer + * @head: &struct plist_head pointer + */ +static inline void +plist_head_init(struct plist_head *head) +{ + INIT_LIST_HEAD(&head->node_list); +} + +/** + * plist_node_init - Dynamic struct plist_node initializer + * @node: &struct plist_node pointer + * @prio: initial node priority + */ +static inline void plist_node_init(struct plist_node *node, int prio) +{ + node->prio = prio; + INIT_LIST_HEAD(&node->prio_list); + INIT_LIST_HEAD(&node->node_list); +} + +extern void plist_add(struct plist_node *node, struct plist_head *head); +extern void plist_del(struct plist_node *node, struct plist_head *head); + +extern void plist_requeue(struct plist_node *node, struct plist_head *head); + +/** + * plist_for_each - iterate over the plist + * @pos: the type * to use as a loop counter + * @head: the head for your list + */ +#define plist_for_each(pos, head) \ + list_for_each_entry(pos, &(head)->node_list, node_list) + +/** + * plist_for_each_continue - continue iteration over the plist + * @pos: the type * to use as a loop cursor + * @head: the head for your list + * + * Continue to iterate over plist, continuing after the current position. + */ +#define plist_for_each_continue(pos, head) \ + list_for_each_entry_continue(pos, &(head)->node_list, node_list) + +/** + * plist_for_each_safe - iterate safely over a plist of given type + * @pos: the type * to use as a loop counter + * @n: another type * to use as temporary storage + * @head: the head for your list + * + * Iterate over a plist of given type, safe against removal of list entry. + */ +#define plist_for_each_safe(pos, n, head) \ + list_for_each_entry_safe(pos, n, &(head)->node_list, node_list) + +/** + * plist_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter + * @head: the head for your list + * @mem: the name of the list_head within the struct + */ +#define plist_for_each_entry(pos, head, mem) \ + list_for_each_entry(pos, &(head)->node_list, mem.node_list) + +/** + * plist_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor + * @head: the head for your list + * @m: the name of the list_head within the struct + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define plist_for_each_entry_continue(pos, head, m) \ + list_for_each_entry_continue(pos, &(head)->node_list, m.node_list) + +/** + * plist_for_each_entry_safe - iterate safely over list of given type + * @pos: the type * to use as a loop counter + * @n: another type * to use as temporary storage + * @head: the head for your list + * @m: the name of the list_head within the struct + * + * Iterate over list of given type, safe against removal of list entry. + */ +#define plist_for_each_entry_safe(pos, n, head, m) \ + list_for_each_entry_safe(pos, n, &(head)->node_list, m.node_list) + +/** + * plist_head_empty - return !0 if a plist_head is empty + * @head: &struct plist_head pointer + */ +static inline int plist_head_empty(const struct plist_head *head) +{ + return list_empty(&head->node_list); +} + +/** + * plist_node_empty - return !0 if plist_node is not on a list + * @node: &struct plist_node pointer + */ +static inline int plist_node_empty(const struct plist_node *node) +{ + return list_empty(&node->node_list); +} + +/* All functions below assume the plist_head is not empty. */ + +/** + * plist_first_entry - get the struct for the first entry + * @head: the &struct plist_head pointer + * @type: the type of the struct this is embedded in + * @member: the name of the list_head within the struct + */ +#ifdef CONFIG_DEBUG_PLIST +# define plist_first_entry(head, type, member) \ + ({ \ + WARN_ON(plist_head_empty(head)); \ + container_of(plist_first(head), type, member); \ + }) +#else +# define plist_first_entry(head, type, member) \ + container_of(plist_first(head), type, member) +#endif + +/** + * plist_last_entry - get the struct for the last entry + * @head: the &struct plist_head pointer + * @type: the type of the struct this is embedded in + * @member: the name of the list_head within the struct + */ +#ifdef CONFIG_DEBUG_PLIST +# define plist_last_entry(head, type, member) \ + ({ \ + WARN_ON(plist_head_empty(head)); \ + container_of(plist_last(head), type, member); \ + }) +#else +# define plist_last_entry(head, type, member) \ + container_of(plist_last(head), type, member) +#endif + +/** + * plist_next - get the next entry in list + * @pos: the type * to cursor + */ +#define plist_next(pos) \ + list_next_entry(pos, node_list) + +/** + * plist_prev - get the prev entry in list + * @pos: the type * to cursor + */ +#define plist_prev(pos) \ + list_prev_entry(pos, node_list) + +/** + * plist_first - return the first node (and thus, highest priority) + * @head: the &struct plist_head pointer + * + * Assumes the plist is _not_ empty. + */ +static inline struct plist_node *plist_first(const struct plist_head *head) +{ + return list_entry(head->node_list.next, + struct plist_node, node_list); +} + +/** + * plist_last - return the last node (and thus, lowest priority) + * @head: the &struct plist_head pointer + * + * Assumes the plist is _not_ empty. + */ +static inline struct plist_node *plist_last(const struct plist_head *head) +{ + return list_entry(head->node_list.prev, + struct plist_node, node_list); +} + +#endif diff --git a/2019/include/pool.h b/2019/include/pool.h new file mode 100644 index 0000000..7f070bd --- /dev/null +++ b/2019/include/pool.h @@ -0,0 +1,90 @@ +/* pool.h - A simple memory pool manager. + * + * Copyright (C) 2021 Bruno Raoult ("br") + * Licensed under the GNU General Public License v3.0 or later. + * Some rights reserved. See COPYING. + * + * You should have received a copy of the GNU General Public License along with this + * program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef POOL_H +#define POOL_H + +#include +#include +#include "list.h" +#include "bits.h" + +#define POOL_NAME_LENGTH (16) /* max name length including trailing \0 */ + +typedef struct { + struct list_head list_blocks; /* list of allocated blocks in pool */ + char data[]; /* objects block */ +} block_t; + +typedef struct { + char name[POOL_NAME_LENGTH]; /* pool name */ + size_t eltsize; /* object size */ + u32 available; /* current available elements */ + u32 allocated; /* total objects allocated */ + u32 growsize; /* number of objects per block allocated */ + u32 nblocks; /* number of blocks allocated */ + struct list_head list_available; /* available nodes */ + struct list_head list_blocks; /* allocated blocks */ +} pool_t; + +/** + * pool_stats - display some pool statistics + * @pool: the pool address. + */ +void pool_stats(pool_t *pool); + +/** + * pool_create - create a new memory pool + * @name: the name to give to the pool. + * @grow: the number of elements to add when no more available. + * @size: the size of an element in pool. + * + * The name will be truncated to 16 characters (including the final '\0'). + * + * Return: The address of the created pool, or NULL if error. + */ +pool_t *pool_create(const char *name, u32 grow, size_t size); + +/** + * pool_get() - Get an element from a pool. + * @pool: The pool address. + * + * Get an object from the pool. + * + * Return: The address of the object, or NULL if error. + */ +void *pool_get(pool_t *pool); + +/** + * pool_add() - Add (free) an element to a pool. + * @pool: The pool address. + * @elt: The address of the object to add to the pool. + * + * The object will be available for further pool_get(). + * + * Return: The current number of available elements in pool (including + * @elt). + */ +u32 pool_add(pool_t *pool, void *elt); + +/** + * pool_destroy() - destroy a pool. + * @pool: The pool address. + * + * Attention: All memory is freed, but no check is done whether all pool + * elements have been released. Referencing any pool object after this call + * will likely imply some memory corruption. + */ +void pool_destroy(pool_t *pool); + +#endif diff --git a/2019/include/rwonce.h b/2019/include/rwonce.h new file mode 100644 index 0000000..90a28bc --- /dev/null +++ b/2019/include/rwonce.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* adaptation of kernel's + * See https://www.kernel.org/doc/Documentation/memory-barriers.txt + */ +/* + * Prevent the compiler from merging or refetching reads or writes. The + * compiler is also forbidden from reordering successive instances of + * READ_ONCE and WRITE_ONCE, but only when the compiler is aware of some + * particular ordering. One way to make the compiler aware of ordering is to + * put the two invocations of READ_ONCE or WRITE_ONCE in different C + * statements. + * + * These two macros will also work on aggregate data types like structs or + * unions. + * + * Their two major use cases are: (1) Mediating communication between + * process-level code and irq/NMI handlers, all running on the same CPU, + * and (2) Ensuring that the compiler does not fold, spindle, or otherwise + * mutilate accesses that either do not require ordering or that interact + * with an explicit memory barrier or atomic instruction that provides the + * required ordering. + */ +#ifndef __BR_RWONCE_H +#define __BR_RWONCE_H + +/************ originally in */ +#if __has_attribute(__error__) +# define __compiletime_error(msg) __attribute__((__error__(msg))) +#else +# define __compiletime_error(msg) +#endif + +/************ originally in */ +/* + * __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving + * non-scalar types unchanged. + */ +/* + * Prefer C11 _Generic for better compile-times and simpler code. Note: 'char' + * is not type-compatible with 'signed char', and we define a separate case. + */ +#define __scalar_type_to_expr_cases(type) \ + unsigned type: (unsigned type)0, \ + signed type: (signed type)0 + +#define __unqual_scalar_typeof(x) \ + typeof(_Generic((x), \ + char: (char)0, \ + __scalar_type_to_expr_cases(char), \ + __scalar_type_to_expr_cases(short), \ + __scalar_type_to_expr_cases(int), \ + __scalar_type_to_expr_cases(long), \ + __scalar_type_to_expr_cases(long long), \ + default: (x))) + +/* Is this type a native word size -- useful for atomic operations */ +#define __native_word(t) \ + (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || \ + sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long)) + +#ifdef __OPTIMIZE__ +# define __compiletime_assert(condition, msg, prefix, suffix) \ + do { \ + extern void prefix ## suffix(void) __compiletime_error(msg); \ + if (!(condition)) \ + prefix ## suffix(); \ + } while (0) +#else +# define __compiletime_assert(condition, msg, prefix, suffix) do { } while (0) +#endif + +#define _compiletime_assert(condition, msg, prefix, suffix) \ + __compiletime_assert(condition, msg, prefix, suffix) + +/** + * compiletime_assert - break build and emit msg if condition is false + * @condition: a compile-time constant condition to check + * @msg: a message to emit if condition is false + * + * In tradition of POSIX assert, this macro will break the build if the + * supplied condition is *false*, emitting the supplied error message if the + * compiler has support to do so. + */ +#define compiletime_assert(condition, msg) \ + _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) + +#define compiletime_assert_atomic_type(t) \ + compiletime_assert(__native_word(t), \ + "Need native word sized stores/loads for atomicity.") + +/************ originally in */ +/* + * Yes, this permits 64-bit accesses on 32-bit architectures. These will + * actually be atomic in some cases (namely Armv7 + LPAE), but for others we + * rely on the access being split into 2x32-bit accesses for a 32-bit quantity + * (e.g. a virtual address) and a strong prevailing wind. + */ +#define compiletime_assert_rwonce_type(t) \ + compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \ + "Unsupported access size for {READ,WRITE}_ONCE().") + +/* + * Use __READ_ONCE() instead of READ_ONCE() if you do not require any + * atomicity. Note that this may result in tears! + */ +#ifndef __READ_ONCE +#define __READ_ONCE(x) (*(const volatile __unqual_scalar_typeof(x) *)&(x)) +#endif + +#define READ_ONCE(x) \ +({ \ + compiletime_assert_rwonce_type(x); \ + __READ_ONCE(x); \ +}) + +#define __WRITE_ONCE(x, val) \ +do { \ + *(volatile typeof(x) *)&(x) = (val); \ +} while (0) + +#define WRITE_ONCE(x, val) \ +do { \ + compiletime_assert_rwonce_type(x); \ + __WRITE_ONCE(x, val); \ +} while (0) + +#endif /* __BR_RWONCE_H */ diff --git a/2019/libsrc/debug.c b/2019/libsrc/debug.c new file mode 100644 index 0000000..0a2635e --- /dev/null +++ b/2019/libsrc/debug.c @@ -0,0 +1,111 @@ +/* debug.c - debug/log management + * + * Copyright (C) 2021-2022 Bruno Raoult ("br") + * Licensed under the GNU General Public License v3.0 or later. + * Some rights reserved. See COPYING. + * + * You should have received a copy of the GNU General Public License along with this + * program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include +#include +#include + +#ifndef DEBUG_DEBUG +#define DEBUG_DEBUG +#endif + +#include "debug.h" + +#define NANOSEC 1000000000 /* nano sec in sec */ +#define MILLISEC 1000000 /* milli sec in sec */ + +static s64 timer_start; /* in nanosecond */ +static u32 debug_level=0; + +void debug_level_set(u32 level) +{ + debug_level = level; + + log(1, "debug level set to %u\n", level); +} + +void debug_init(u32 level) +{ + struct timespec timer; + + debug_level_set(level); + if (!clock_gettime(CLOCK_MONOTONIC, &timer)) { + timer_start = timer.tv_sec * NANOSEC + timer.tv_nsec; + } + else { + timer_start = 0; + } + log(0, "timer started.\n"); +} + +inline static s64 timer_elapsed() +{ + struct timespec timer; + + clock_gettime(CLOCK_MONOTONIC, &timer); + return (timer.tv_sec * NANOSEC + timer.tv_nsec) - timer_start; +} + + +/* void debug - log function + * @timestamp : boolean + * @indent : indent level (2 spaces each) + * @src : source file/func name (or NULL) + * @line : line number + */ +void debug(u32 level, bool timestamp, u32 indent, const char *src, + u32 line, const char *fmt, ...) +{ + if (level > debug_level) + return; + + va_list ap; + + if (indent) + printf("%*s", 2*(indent-1), ""); + + if (timestamp) { + s64 diff = timer_elapsed(); + printf("%ld.%03ld ", diff/NANOSEC, (diff/1000000)%1000); + printf("%010ld ", diff); + } + + if (src) { + if (line) + printf("[%s:%u] ", src, line); + else + printf("[%s] ", src); + } + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +#ifdef BIN_debug +#include + +int main() +{ + int foo=1; + debug_init(5); + + log(0, "log0=%d\n", foo++); + log(1, "log1=%d\n", foo++); + log(2, "log2=%d\n", foo++); + log_i(2, "log_i 2=%d\n", foo++); + log_i(5, "log_i 5=%d\n", foo++); + log_i(6, "log_i 6=%d\n", foo++); + log_it(4, "log_it 4=%d\n", foo++); + log_f(1, "log_f 5=%d\n", foo++); +} +#endif diff --git a/2019/libsrc/plist.c b/2019/libsrc/plist.c new file mode 100644 index 0000000..72e1fb1 --- /dev/null +++ b/2019/libsrc/plist.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * adapted from Linux kernel lib/plist.c + * + * Descending-priority-sorted double-linked list + * + * (C) 2002-2003 Intel Corp + * Inaky Perez-Gonzalez . + * + * 2001-2005 (c) MontaVista Software, Inc. + * Daniel Walker + * + * (C) 2005 Thomas Gleixner + * + * Simplifications of the original code by + * Oleg Nesterov + * + * Based on simple lists (include/linux/list.h). + * + * This file contains the add / del functions which are considered to + * be too large to inline. See include/linux/plist.h for further + * information. + */ + +#include "plist.h" +#include "bug.h" + +#ifdef DEBUG_PLIST + +static struct plist_head test_head; + +static void plist_check_prev_next(struct list_head *t, struct list_head *p, + struct list_head *n) +{ + WARN(n->prev != p || p->next != n, + "top: %p, n: %p, p: %p\n" + "prev: %p, n: %p, p: %p\n" + "next: %p, n: %p, p: %p\n", + t, t->next, t->prev, + p, p->next, p->prev, + n, n->next, n->prev); +} + +static void plist_check_list(struct list_head *top) +{ + struct list_head *prev = top, *next = top->next; + + plist_check_prev_next(top, prev, next); + while (next != top) { + prev = next; + next = prev->next; + plist_check_prev_next(top, prev, next); + } +} + +static void plist_check_head(struct plist_head *head) +{ + if (!plist_head_empty(head)) + plist_check_list(&plist_first(head)->prio_list); + plist_check_list(&head->node_list); +} + +#else +# define plist_check_head(h) do { } while (0) +#endif + +/** + * plist_add - add @node to @head + * + * @node: &struct plist_node pointer + * @head: &struct plist_head pointer + */ +void plist_add(struct plist_node *node, struct plist_head *head) +{ + struct plist_node *first, *iter, *prev = NULL; + struct list_head *node_next = &head->node_list; + + plist_check_head(head); + WARN_ON(!plist_node_empty(node)); + WARN_ON(!list_empty(&node->prio_list)); + + if (plist_head_empty(head)) + goto ins_node; + + first = iter = plist_first(head); + + do { + if (node->prio < iter->prio) { + node_next = &iter->node_list; + break; + } + + prev = iter; + iter = list_entry(iter->prio_list.next, + struct plist_node, prio_list); + } while (iter != first); + + if (!prev || prev->prio != node->prio) + list_add_tail(&node->prio_list, &iter->prio_list); +ins_node: + list_add_tail(&node->node_list, node_next); + + plist_check_head(head); +} + +/** + * plist_del - Remove a @node from plist. + * + * @node: &struct plist_node pointer - entry to be removed + * @head: &struct plist_head pointer - list head + */ +void plist_del(struct plist_node *node, struct plist_head *head) +{ + plist_check_head(head); + + if (!list_empty(&node->prio_list)) { + if (node->node_list.next != &head->node_list) { + struct plist_node *next; + + next = list_entry(node->node_list.next, + struct plist_node, node_list); + + /* add the next plist_node into prio_list */ + if (list_empty(&next->prio_list)) + list_add(&next->prio_list, &node->prio_list); + } + list_del_init(&node->prio_list); + } + + list_del_init(&node->node_list); + + plist_check_head(head); +} + +/** + * plist_requeue - Requeue @node at end of same-prio entries. + * + * This is essentially an optimized plist_del() followed by + * plist_add(). It moves an entry already in the plist to + * after any other same-priority entries. + * + * @node: &struct plist_node pointer - entry to be moved + * @head: &struct plist_head pointer - list head + */ +void plist_requeue(struct plist_node *node, struct plist_head *head) +{ + struct plist_node *iter; + struct list_head *node_next = &head->node_list; + + plist_check_head(head); + BUG_ON(plist_head_empty(head)); + BUG_ON(plist_node_empty(node)); + + if (node == plist_last(head)) + return; + + iter = plist_next(node); + + if (node->prio != iter->prio) + return; + + plist_del(node, head); + + plist_for_each_continue(iter, head) { + if (node->prio != iter->prio) { + node_next = &iter->node_list; + break; + } + } + list_add_tail(&node->node_list, node_next); + + plist_check_head(head); +} diff --git a/2019/libsrc/pool.c b/2019/libsrc/pool.c new file mode 100644 index 0000000..22c6b18 --- /dev/null +++ b/2019/libsrc/pool.c @@ -0,0 +1,222 @@ +/* pool.c - A simple pool manager. + * + * Copyright (C) 2021-2022 Bruno Raoult ("br") + * Licensed under the GNU General Public License v3.0 or later. + * Some rights reserved. See COPYING. + * + * You should have received a copy of the GNU General Public License along with this + * program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include +#include +#include +#include +#include + +#include "list.h" +#include "pool.h" +#include "debug.h" +#include "bits.h" + +void pool_stats(pool_t *pool) +{ + if (pool) { + block_t *block; + + log_f(1, "[%s] pool [%p]: blocks:%u avail:%u alloc:%u grow:%u eltsize:%lu\n", + pool->name, (void *)pool, pool->nblocks, pool->available, pool->allocated, + pool->growsize, pool->eltsize); + log(5, "\tblocks: "); + list_for_each_entry(block, &pool->list_blocks, list_blocks) { + log(5, "%p ", block); + } + log(5, "\n"); + } +} + +pool_t *pool_create(const char *name, u32 growsize, size_t eltsize) +{ + pool_t *pool; + +# ifdef DEBUG_POOL + log_f(1, "name=[%s] growsize=%u eltsize=%lu\n", + name, growsize, eltsize); +# endif + /* we need at least sizeof(struct list_head) space in pool elements + */ + if (eltsize < sizeof (struct list_head)) { +# ifdef DEBUG_POOL + log_f(1, "[%s]: structure size too small (%lu < %lu), adjusting to %lu.\n", + name, eltsize, sizeof(struct list_head), sizeof(struct list_head)); +# endif + eltsize = sizeof(struct list_head); + } + if ((pool = malloc(sizeof (*pool)))) { + strncpy(pool->name, name, POOL_NAME_LENGTH - 1); + pool->name[POOL_NAME_LENGTH - 1] = 0; + pool->growsize = growsize; + pool->eltsize = eltsize; + pool->available = 0; + pool->allocated = 0; + pool->nblocks = 0; + INIT_LIST_HEAD(&pool->list_available); + INIT_LIST_HEAD(&pool->list_blocks); + } else { + errno = ENOMEM; + } + return pool; +} + +static u32 _pool_add(pool_t *pool, struct list_head *elt) +{ +# ifdef DEBUG_POOL + log_f(6, "pool=%p &head=%p elt=%p off1=%lu off2=%lu\n", + (void *)pool, + (void *)&pool->list_available, + (void *)elt, + (void *)&pool->list_available-(void *)pool, + offsetof(pool_t, list_available)); +# endif + + list_add(elt, &pool->list_available); + return ++pool->available; +} + +u32 pool_add(pool_t *pool, void *elt) +{ + return _pool_add(pool, elt); +} + +static struct list_head *_pool_get(pool_t *pool) +{ + struct list_head *res = pool->list_available.next; + pool->available--; + list_del(res); + return res; +} + +void *pool_get(pool_t *pool) +{ + if (!pool) + return NULL; + if (!pool->available) { + block_t *block = malloc(sizeof(block_t) + pool->eltsize * pool->growsize); + if (!block) { +# ifdef DEBUG_POOL + log_f(1, "[%s]: failed block allocation\n", pool->name); +# endif + errno = ENOMEM; + return NULL; + } + + /* maintain list of allocated blocks + */ + list_add(&block->list_blocks, &pool->list_blocks); + pool->nblocks++; + +# ifdef DEBUG_POOL + log_f(1, "[%s]: growing pool from %u to %u elements. block=%p nblocks=%u\n", + pool->name, + pool->allocated, + pool->allocated + pool->growsize, + block, + pool->nblocks); +# endif + + pool->allocated += pool->growsize; + for (u32 i = 0; i < pool->growsize; ++i) { + void *cur = block->data + i * pool->eltsize; +# ifdef DEBUG_POOL + log_f(7, "alloc=%p cur=%p\n", block, cur); +# endif + _pool_add(pool, (struct list_head *)cur); + } + } + /* this is the effective address of the object (and also the + * pool list_head address) + */ + return _pool_get(pool); +} + +void pool_destroy(pool_t *pool) +{ + block_t *block, *tmp; + if (!pool) + return; + /* release memory blocks */ +# ifdef DEBUG_POOL + log_f(1, "[%s]: releasing %d blocks and main structure\n", pool->name, pool->nblocks); + log(5, "blocks:"); +# endif + list_for_each_entry_safe(block, tmp, &pool->list_blocks, list_blocks) { + list_del(&block->list_blocks); + free(block); +# ifdef DEBUG_POOL + log(5, " %p", block); +# endif + } +# ifdef DEBUG_POOL + log(5, "\n"); +# endif + free(pool); +} + +#ifdef BIN_pool +struct d { + u16 data1; + char c; + struct list_head list; +}; + +static LIST_HEAD (head); + +int main(int ac, char**av) +{ + pool_t *pool; + int total; + int action=0; + u16 icur=0; + char ccur='z'; + struct d *elt; + + debug_init(3); + log_f(1, "%s: sizeof(d)=%lu sizeof(*d)=%lu off=%lu\n", *av, sizeof(elt), + sizeof(*elt), offsetof(struct d, list)); + + if ((pool = pool_create("dummy", 3, sizeof(*elt)))) { + pool_stats(pool); + for (int cur=1; curdata1 = icur++; + elt->c = ccur--; + list_add(&elt->list, &head); + } + pool_stats(pool); + action = 1; + } else { /* remove one elt from list */ + log_f(2, "deleting %d elements\n", total); + for (int i = 0; i < total; ++i) { + if (!list_empty(&head)) { + elt = list_last_entry(&head, struct d, list); + printf("elt=[%d, %c]\n", elt->data1, elt->c); + list_del(&elt->list); + pool_add(pool, elt); + } + } + pool_stats(pool); + action = 0; + } + } + } + pool_stats(pool); + pool_destroy(pool); +} +#endif