Added bit allocator from NOVA.

This commit is contained in:
Michael Mueller
2024-10-28 13:26:23 +01:00
parent 2925ae7737
commit 453f5e69ea
5 changed files with 288 additions and 0 deletions

61
src/mx/util/atomic.h Normal file
View File

@@ -0,0 +1,61 @@
/*
* Atomic Operations
*
* Copyright (C) 2009-2011 Udo Steinberg <udo@hypervisor.org>
* Economic rights: Technische Universitaet Dresden (Germany)
*
* This file is part of the NOVA microhypervisor.
*
* NOVA is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* NOVA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*/
#pragma once
#include "compiler.h"
class Atomic
{
public:
template <typename T>
static inline bool cmp_swap (T &ptr, T o, T n) { return __sync_bool_compare_and_swap (&ptr, o, n); }
template <typename T>
static inline T add (T &ptr, T v) { return __sync_add_and_fetch (&ptr, v); }
template <typename T>
static inline T sub (T &ptr, T v) { return __sync_sub_and_fetch (&ptr, v); }
template <typename T>
static inline void set_mask (T &ptr, T v) { __sync_or_and_fetch (&ptr, v); }
template <typename T>
static inline void clr_mask (T &ptr, T v) { __sync_and_and_fetch (&ptr, ~v); }
template <typename T>
static inline bool test_set_bit (T &val, unsigned long bit)
{
bool ret;
asm volatile ("lock; bts %2, %1; setc %0" : "=q" (ret), "+m" (val) : "ir" (bit) : "cc");
return ret;
}
template <typename T>
static inline bool test_clr_bit (T &val, unsigned long bit)
{
bool ret;
asm volatile ("lock; btr %2, %1; setc %0" : "=q" (ret), "+m" (val) : "ir" (bit) : "cc");
return ret;
}
};

154
src/mx/util/bit_alloc.h Normal file
View File

@@ -0,0 +1,154 @@
/*
* Bit allocator
*
* Copyright (C) 2020 Alexander Boettcher, Genode Labs GmbH
*
* This file is part of the NOVA microhypervisor.
*
* NOVA is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* NOVA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*/
#pragma once
#include "bits.h"
#include "atomic.h"
namespace mx::util {
template<unsigned C, unsigned INV> class Bit_alloc;
}
template<unsigned C, unsigned INV>
class mx::util::Bit_alloc
{
private:
alignas(64) std::uint64_t bits [C / 8 / sizeof(std::uint64_t)];
std::uint64_t last { 0 };
enum {
BITS_CNT = sizeof(bits[0]) * 8,
MAX = sizeof(bits) / sizeof(bits [0])
};
public:
inline std::uint64_t max() const { return C; }
inline Bit_alloc()
{
static_assert(MAX*BITS_CNT == C, "bit allocator");
static_assert(INV < C, "bit allocator");
Atomic::test_set_bit(bits[INV / BITS_CNT], INV % BITS_CNT);
}
inline std::uint64_t alloc_with_mask(std::uint64_t bitmask[C/8/sizeof(std::uint64_t)], bool inverse = false)
{
for (std::uint64_t i = ACCESS_ONCE(last), j = 0; j < MAX; i++, j++)
{
i %= MAX;
std::uint64_t mask = ~bits[i] & (inverse ? ~bitmask[i] : bitmask[i]);
if (mask == 0UL)
continue;
long b = bit_scan_forward (mask);
if (b < 0 || b >= BITS_CNT || Atomic::test_set_bit (bits[i], b)) {
j--;
i--;
continue;
}
if (bits[i] != ~0UL && last != i)
last = i;
return i * BITS_CNT + b;
}
return INV;
}
inline std::uint64_t alloc()
{
return alloc_with_mask(bits, true);
}
inline void release(std::uint64_t const id)
{
if (id == INV || id >= C)
return;
std::uint64_t i = id / BITS_CNT;
std::uint64_t b = id % BITS_CNT;
while (ACCESS_ONCE(bits[i]) & (1ul << b))
Atomic::test_clr_bit (ACCESS_ONCE(bits[i]), b);
}
inline bool reserve(std::uint64_t const id)
{
if (id == INV || id >= C)
return false;
std::uint64_t i = id / BITS_CNT;
std::uint64_t b = id % BITS_CNT;
return Atomic::test_set_bit (ACCESS_ONCE(bits[i]), b);
}
void reserve(std::uint64_t const start, std::uint64_t const count)
{
if (start >= C)
return;
std::uint64_t i = start / BITS_CNT;
std::uint64_t b = start % BITS_CNT;
std::uint64_t cnt = count > C ? C : count;
if (start + cnt > C)
cnt = C - start;
while (cnt) {
std::uint64_t const c = (cnt > BITS_CNT) ? std::uint64_t(BITS_CNT) : cnt;
std::uint64_t const bc = (c > (BITS_CNT - b)) ? std::uint64_t(BITS_CNT - b) : c;
if (bits[i] != ~0UL) {
if (bc >= BITS_CNT) {
bits[i] = ~0UL;
} else {
bits[i] |= ((1ul << bc) - 1) << b;
}
}
i++;
cnt -= bc;
b = 0;
}
}
void reserve_with_mask(std::uint64_t const mask, std::uint64_t const offset)
{
Atomic::set_mask(bits[offset], mask);
}
void dump_trace()
{
for (int i = 0; i < MAX; i++)
trace(0, "bitmap[%d]: %lx", i, bits[i]);
}
};

14
src/mx/util/bits.old Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
namespace mx::util {
inline long int bit_scan_forward(std::uint64_t val)
{
if (!val)
return -1;
asm volatile("bsf %1, %0" : "=r"(val) : "rm"(val));
return val;
}
}

26
src/mx/util/compiler.h Normal file
View File

@@ -0,0 +1,26 @@
/*
* Compiler Macros
*
* Copyright (C) 2009-2011 Udo Steinberg <udo@hypervisor.org>
* Economic rights: Technische Universitaet Dresden (Germany)
*
* Copyright (C) 2012-2013 Udo Steinberg, Intel Corporation.
*
* This file is part of the NOVA microhypervisor.
*
* NOVA is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* NOVA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*/
#pragma once
#define EXPECT_FALSE(X) __builtin_expect(!!(X), 0)
#define EXPECT_TRUE(X) __builtin_expect(!!(X), 1)
#define ACCESS_ONCE(x) (*static_cast<volatile typeof(x) *>(&(x)))

33
src/mx/util/util.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* Utility Functions
*
* Copyright (C) 2009-2011 Udo Steinberg <udo@hypervisor.org>
* Economic rights: Technische Universitaet Dresden (Germany)
*
* This file is part of the NOVA microhypervisor.
*
* NOVA is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* NOVA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*/
#pragma once
#include "compiler.h"
template <typename T>
static inline T min (T v1, T v2)
{
return v1 < v2 ? v1 : v2;
}
template <typename T>
static inline T max (T v1, T v2)
{
return v1 > v2 ? v1 : v2;
}