mirror of
https://github.com/mmueller41/mxtasking.git
synced 2026-01-21 12:42:57 +01:00
Added bit allocator from NOVA.
This commit is contained in:
61
src/mx/util/atomic.h
Normal file
61
src/mx/util/atomic.h
Normal 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
154
src/mx/util/bit_alloc.h
Normal 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
14
src/mx/util/bits.old
Normal 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
26
src/mx/util/compiler.h
Normal 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
33
src/mx/util/util.h
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user