Compare commits
No commits in common. "ed82a18e2aab203e80bce433d74e07a63c6db58b" and "12489a4c6b3021d84893d8adef2f9b51e2310c94" have entirely different histories.
ed82a18e2a
...
12489a4c6b
|
|
@ -9,35 +9,29 @@
|
||||||
#include <BAN/Formatter.h>
|
#include <BAN/Formatter.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#define __debug_putchar [](int c) { putc_unlocked(c, stddbg); }
|
#define __debug_putchar [](int c) { putc(c, stddbg); }
|
||||||
|
|
||||||
#define dprintln(...) \
|
#define dprintln(...) \
|
||||||
do { \
|
do { \
|
||||||
flockfile(stddbg); \
|
|
||||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
BAN::Formatter::print(__debug_putchar,"\n"); \
|
BAN::Formatter::print(__debug_putchar,"\n"); \
|
||||||
fflush(stddbg); \
|
fflush(stddbg); \
|
||||||
funlockfile(stddbg); \
|
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define dwarnln(...) \
|
#define dwarnln(...) \
|
||||||
do { \
|
do { \
|
||||||
flockfile(stddbg); \
|
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
||||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
||||||
fflush(stddbg); \
|
fflush(stddbg); \
|
||||||
funlockfile(stddbg); \
|
|
||||||
} while(false)
|
} while(false)
|
||||||
|
|
||||||
#define derrorln(...) \
|
#define derrorln(...) \
|
||||||
do { \
|
do { \
|
||||||
flockfile(stddbg); \
|
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
||||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||||
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
||||||
fflush(stddbg); \
|
fflush(stddbg); \
|
||||||
funlockfile(stddbg); \
|
|
||||||
} while(false)
|
} while(false)
|
||||||
|
|
||||||
#define dprintln_if(cond, ...) \
|
#define dprintln_if(cond, ...) \
|
||||||
|
|
|
||||||
|
|
@ -28,28 +28,36 @@ namespace Kernel
|
||||||
BAN_NON_COPYABLE(BlockBufferWrapper);
|
BAN_NON_COPYABLE(BlockBufferWrapper);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BlockBufferWrapper(BAN::Span<uint8_t> buffer, void (*callback)(void*, const uint8_t*), void* argument)
|
BlockBufferWrapper(BAN::Span<uint8_t> buffer, bool* used, Mutex* mutex, ThreadBlocker* blocker)
|
||||||
: m_buffer(buffer)
|
: m_buffer(buffer)
|
||||||
, m_callback(callback)
|
, m_used(used)
|
||||||
, m_argument(argument)
|
, m_mutex(mutex)
|
||||||
{ }
|
, m_blocker(blocker)
|
||||||
|
{
|
||||||
|
ASSERT(m_used && *m_used);
|
||||||
|
}
|
||||||
BlockBufferWrapper(BlockBufferWrapper&& other) { *this = BAN::move(other); }
|
BlockBufferWrapper(BlockBufferWrapper&& other) { *this = BAN::move(other); }
|
||||||
~BlockBufferWrapper()
|
~BlockBufferWrapper()
|
||||||
{
|
{
|
||||||
if (m_callback == nullptr)
|
if (m_used == nullptr)
|
||||||
return;
|
return;
|
||||||
m_callback(m_argument, m_buffer.data());
|
m_mutex->lock();
|
||||||
|
*m_used = false;
|
||||||
|
m_blocker->unblock();
|
||||||
|
m_mutex->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockBufferWrapper& operator=(BlockBufferWrapper&& other)
|
BlockBufferWrapper& operator=(BlockBufferWrapper&& other)
|
||||||
{
|
{
|
||||||
this->m_buffer = other.m_buffer;
|
this->m_buffer = other.m_buffer;
|
||||||
this->m_callback = other.m_callback;
|
this->m_used = other.m_used;
|
||||||
this->m_argument = other.m_argument;
|
this->m_mutex = other.m_mutex;
|
||||||
|
this->m_blocker = other.m_blocker;
|
||||||
|
|
||||||
other.m_buffer = {};
|
other.m_buffer = {};
|
||||||
other.m_callback = nullptr;
|
other.m_used = nullptr;
|
||||||
other.m_argument = nullptr;
|
other.m_mutex = nullptr;
|
||||||
|
other.m_blocker = nullptr;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
@ -67,8 +75,9 @@ namespace Kernel
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BAN::Span<uint8_t> m_buffer;
|
BAN::Span<uint8_t> m_buffer;
|
||||||
void (*m_callback)(void*, const uint8_t*);
|
bool* m_used;
|
||||||
void* m_argument;
|
Mutex* m_mutex;
|
||||||
|
ThreadBlocker* m_blocker;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -121,9 +130,6 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void> initialize(size_t block_size);
|
BAN::ErrorOr<void> initialize(size_t block_size);
|
||||||
|
|
||||||
private:
|
|
||||||
void destroy_callback(const uint8_t* buffer_ptr);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct BlockBuffer
|
struct BlockBuffer
|
||||||
{
|
{
|
||||||
|
|
@ -131,20 +137,10 @@ namespace Kernel
|
||||||
bool used { false };
|
bool used { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ThreadInfo
|
|
||||||
{
|
|
||||||
pid_t tid { 0 };
|
|
||||||
size_t buffers { 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr size_t max_threads = 8;
|
|
||||||
static constexpr size_t max_buffers_per_thread = 6;
|
|
||||||
|
|
||||||
Mutex m_buffer_mutex;
|
Mutex m_buffer_mutex;
|
||||||
ThreadBlocker m_buffer_blocker;
|
ThreadBlocker m_buffer_blocker;
|
||||||
BAN::Array<BlockBuffer, max_threads * max_buffers_per_thread> m_buffers;
|
BAN::Array<BlockBuffer, 16> m_buffers;
|
||||||
BAN::Array<ThreadInfo, max_threads> m_thread_infos;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -346,19 +346,6 @@ namespace Kernel
|
||||||
|
|
||||||
vaddr_t m_shared_page_vaddr { 0 };
|
vaddr_t m_shared_page_vaddr { 0 };
|
||||||
|
|
||||||
struct futex_t
|
|
||||||
{
|
|
||||||
ThreadBlocker blocker;
|
|
||||||
uint32_t waiters { 0 };
|
|
||||||
uint32_t to_wakeup { 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
static BAN::HashMap<paddr_t, BAN::UniqPtr<futex_t>> s_futexes;
|
|
||||||
static Mutex s_futex_lock;
|
|
||||||
|
|
||||||
BAN::HashMap<paddr_t, BAN::UniqPtr<futex_t>> m_futexes;
|
|
||||||
Mutex m_futex_lock;
|
|
||||||
|
|
||||||
BAN::Vector<Thread*> m_threads;
|
BAN::Vector<Thread*> m_threads;
|
||||||
|
|
||||||
struct pthread_info_t
|
struct pthread_info_t
|
||||||
|
|
|
||||||
|
|
@ -532,88 +532,22 @@ namespace Kernel
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ext2FS::BlockBufferManager::destroy_callback(const uint8_t* buffer_ptr)
|
|
||||||
{
|
|
||||||
const auto tid = Thread::current_tid();
|
|
||||||
|
|
||||||
LockGuard _(m_buffer_mutex);
|
|
||||||
|
|
||||||
for (auto& buffer : m_buffers)
|
|
||||||
{
|
|
||||||
if (buffer.buffer.data() != buffer_ptr)
|
|
||||||
continue;
|
|
||||||
ASSERT(buffer.used);
|
|
||||||
buffer.used = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& info : m_thread_infos)
|
|
||||||
{
|
|
||||||
if (info.tid != tid)
|
|
||||||
continue;
|
|
||||||
ASSERT(info.buffers > 0);
|
|
||||||
info.buffers--;
|
|
||||||
if (info.buffers != 0)
|
|
||||||
break;
|
|
||||||
info.tid = 0;
|
|
||||||
m_buffer_blocker.unblock();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<Ext2FS::BlockBufferWrapper> Ext2FS::BlockBufferManager::get_buffer()
|
BAN::ErrorOr<Ext2FS::BlockBufferWrapper> Ext2FS::BlockBufferManager::get_buffer()
|
||||||
{
|
{
|
||||||
const auto tid = Thread::current_tid();
|
|
||||||
ASSERT(tid);
|
|
||||||
|
|
||||||
LockGuard _(m_buffer_mutex);
|
LockGuard _(m_buffer_mutex);
|
||||||
|
|
||||||
ThreadInfo* thread_info = nullptr;
|
for (;;)
|
||||||
|
|
||||||
for (auto& info : m_thread_infos)
|
|
||||||
{
|
{
|
||||||
if (info.tid != tid)
|
|
||||||
continue;
|
|
||||||
thread_info = &info;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (thread_info == nullptr)
|
|
||||||
{
|
|
||||||
for (auto& info : m_thread_infos)
|
|
||||||
{
|
|
||||||
if (info.tid != 0)
|
|
||||||
continue;
|
|
||||||
thread_info = &info;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread_info)
|
|
||||||
{
|
|
||||||
thread_info->tid = tid;
|
|
||||||
thread_info->buffers = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker, &m_buffer_mutex));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(thread_info->buffers < max_buffers_per_thread);
|
|
||||||
thread_info->buffers++;
|
|
||||||
|
|
||||||
for (auto& buffer : m_buffers)
|
for (auto& buffer : m_buffers)
|
||||||
{
|
{
|
||||||
if (buffer.used)
|
if (buffer.used)
|
||||||
continue;
|
continue;
|
||||||
buffer.used = true;
|
buffer.used = true;
|
||||||
return Ext2FS::BlockBufferWrapper {
|
return Ext2FS::BlockBufferWrapper(buffer.buffer.span(), &buffer.used, &m_buffer_mutex, &m_buffer_blocker);
|
||||||
buffer.buffer.span(),
|
|
||||||
[](void* self, const uint8_t* buffer) { static_cast<BlockBufferManager*>(self)->destroy_callback(buffer); },
|
|
||||||
this
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker, &m_buffer_mutex));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Ext2FS::BlockBufferManager::initialize(size_t block_size)
|
BAN::ErrorOr<void> Ext2FS::BlockBufferManager::initialize(size_t block_size)
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,14 @@ namespace Kernel
|
||||||
static BAN::Vector<Process*> s_processes;
|
static BAN::Vector<Process*> s_processes;
|
||||||
static RecursiveSpinLock s_process_lock;
|
static RecursiveSpinLock s_process_lock;
|
||||||
|
|
||||||
BAN::HashMap<paddr_t, BAN::UniqPtr<Process::futex_t>> Process::s_futexes;
|
struct futex_t
|
||||||
Mutex Process::s_futex_lock;
|
{
|
||||||
|
ThreadBlocker blocker;
|
||||||
|
uint32_t waiters { 0 };
|
||||||
|
uint32_t to_wakeup { 0 };
|
||||||
|
};
|
||||||
|
static BAN::HashMap<paddr_t, BAN::UniqPtr<futex_t>> s_futexes;
|
||||||
|
static Mutex s_futex_lock;
|
||||||
|
|
||||||
static void for_each_process(const BAN::Function<BAN::Iteration(Process&)>& callback)
|
static void for_each_process(const BAN::Function<BAN::Iteration(Process&)>& callback)
|
||||||
{
|
{
|
||||||
|
|
@ -3101,9 +3107,12 @@ namespace Kernel
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
const bool is_realtime = (op & FUTEX_REALTIME);
|
const bool is_realtime = (op & FUTEX_REALTIME);
|
||||||
const bool is_private = (op & FUTEX_PRIVATE);
|
|
||||||
op &= ~(FUTEX_PRIVATE | FUTEX_REALTIME);
|
op &= ~(FUTEX_PRIVATE | FUTEX_REALTIME);
|
||||||
|
|
||||||
|
// TODO: possibly optimize private futexes?
|
||||||
|
|
||||||
|
LockGuard _(s_futex_lock);
|
||||||
|
|
||||||
auto* buffer_region = TRY(validate_and_pin_pointer_access(addr, sizeof(uint32_t), false));
|
auto* buffer_region = TRY(validate_and_pin_pointer_access(addr, sizeof(uint32_t), false));
|
||||||
BAN::ScopeGuard pin_guard([&] { if (buffer_region) buffer_region->unpin(); });
|
BAN::ScopeGuard pin_guard([&] { if (buffer_region) buffer_region->unpin(); });
|
||||||
|
|
||||||
|
|
@ -3113,26 +3122,17 @@ namespace Kernel
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case FUTEX_WAIT:
|
case FUTEX_WAIT:
|
||||||
break;
|
{
|
||||||
case FUTEX_WAKE:
|
if (BAN::atomic_load(*addr) != val)
|
||||||
abstime = nullptr;
|
return BAN::Error::from_errno(EAGAIN);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return BAN::Error::from_errno(ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64_t wake_time_ns =
|
const uint64_t wake_time_ns =
|
||||||
TRY([abstime, is_realtime, this]() -> BAN::ErrorOr<uint64_t>
|
TRY([abstime, is_realtime, this]() -> BAN::ErrorOr<uint64_t>
|
||||||
{
|
{
|
||||||
if (abstime == nullptr)
|
if (abstime == nullptr)
|
||||||
return BAN::numeric_limits<uint64_t>::max();
|
return BAN::numeric_limits<uint64_t>::max();
|
||||||
const uint64_t abs_ns =
|
|
||||||
TRY([abstime, this]() -> BAN::ErrorOr<uint64_t>
|
|
||||||
{
|
|
||||||
LockGuard _(m_process_lock);
|
|
||||||
TRY(validate_pointer_access(abstime, sizeof(*abstime), false));
|
TRY(validate_pointer_access(abstime, sizeof(*abstime), false));
|
||||||
return abstime->tv_sec * 1'000'000'000 + abstime->tv_nsec;
|
const uint64_t abs_ns = abstime->tv_sec * 1'000'000'000 + abstime->tv_nsec;
|
||||||
}());
|
|
||||||
if (!is_realtime)
|
if (!is_realtime)
|
||||||
return abs_ns;
|
return abs_ns;
|
||||||
const auto realtime = SystemTimer::get().real_time();
|
const auto realtime = SystemTimer::get().real_time();
|
||||||
|
|
@ -3142,32 +3142,20 @@ namespace Kernel
|
||||||
return SystemTimer::get().ns_since_boot() + (abs_ns - real_ns);
|
return SystemTimer::get().ns_since_boot() + (abs_ns - real_ns);
|
||||||
}());
|
}());
|
||||||
|
|
||||||
auto& futex_lock = is_private ? m_futex_lock : s_futex_lock;
|
auto it = s_futexes.find(paddr);
|
||||||
auto& futexes = is_private ? m_futexes : s_futexes;
|
if (it == s_futexes.end())
|
||||||
|
it = TRY(s_futexes.emplace(paddr, TRY(BAN::UniqPtr<futex_t>::create())));
|
||||||
LockGuard _(futex_lock);
|
|
||||||
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case FUTEX_WAIT:
|
|
||||||
{
|
|
||||||
if (BAN::atomic_load(*addr) != val)
|
|
||||||
return BAN::Error::from_errno(EAGAIN);
|
|
||||||
|
|
||||||
auto it = futexes.find(paddr);
|
|
||||||
if (it == futexes.end())
|
|
||||||
it = TRY(futexes.emplace(paddr, TRY(BAN::UniqPtr<futex_t>::create())));
|
|
||||||
futex_t* const futex = it->value.ptr();
|
futex_t* const futex = it->value.ptr();
|
||||||
|
|
||||||
futex->waiters++;
|
futex->waiters++;
|
||||||
BAN::ScopeGuard _([&futexes, futex, paddr] {
|
BAN::ScopeGuard _([futex, paddr] {
|
||||||
if (--futex->waiters == 0)
|
if (--futex->waiters == 0)
|
||||||
futexes.remove(paddr);
|
s_futexes.remove(paddr);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
TRY(Thread::current().block_or_eintr_or_waketime_ns(futex->blocker, wake_time_ns, true, &futex_lock));
|
TRY(Thread::current().block_or_eintr_or_waketime_ns(futex->blocker, wake_time_ns, true, &s_futex_lock));
|
||||||
if (BAN::atomic_load(*addr) == val || futex->to_wakeup == 0)
|
if (BAN::atomic_load(*addr) == val || futex->to_wakeup == 0)
|
||||||
continue;
|
continue;
|
||||||
futex->to_wakeup--;
|
futex->to_wakeup--;
|
||||||
|
|
@ -3176,8 +3164,8 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
case FUTEX_WAKE:
|
case FUTEX_WAKE:
|
||||||
{
|
{
|
||||||
auto it = futexes.find(paddr);
|
auto it = s_futexes.find(paddr);
|
||||||
if (it == futexes.end())
|
if (it == s_futexes.end())
|
||||||
return 0;
|
return 0;
|
||||||
futex_t* const futex = it->value.ptr();
|
futex_t* const futex = it->value.ptr();
|
||||||
|
|
||||||
|
|
@ -3190,6 +3178,8 @@ namespace Kernel
|
||||||
futex->blocker.unblock();
|
futex->blocker.unblock();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return BAN::Error::from_errno(ENOSYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
|
|
||||||
|
|
@ -884,11 +884,9 @@ int pthread_mutex_unlock(pthread_mutex_t* mutex)
|
||||||
mutex->lock_depth--;
|
mutex->lock_depth--;
|
||||||
if (mutex->lock_depth == 0)
|
if (mutex->lock_depth == 0)
|
||||||
{
|
{
|
||||||
const int op = FUTEX_WAKE | (mutex->attr.shared ? 0 : FUTEX_PRIVATE);
|
|
||||||
|
|
||||||
BAN::atomic_store(mutex->futex, 0, BAN::memory_order_release);
|
BAN::atomic_store(mutex->futex, 0, BAN::memory_order_release);
|
||||||
if (BAN::atomic_load(mutex->waiters))
|
if (BAN::atomic_load(mutex->waiters))
|
||||||
futex(op, &mutex->futex, 1, nullptr);
|
futex(FUTEX_WAKE, &mutex->futex, 1, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,8 @@ int sem_getvalue(sem_t* __restrict sem, int* __restrict sval)
|
||||||
int sem_post(sem_t* sem)
|
int sem_post(sem_t* sem)
|
||||||
{
|
{
|
||||||
const auto old = BAN::atomic_fetch_add(sem->value, 1);
|
const auto old = BAN::atomic_fetch_add(sem->value, 1);
|
||||||
const int op = FUTEX_WAKE | (sem->shared ? 0 : FUTEX_PRIVATE);
|
|
||||||
if (old == 0)
|
if (old == 0)
|
||||||
futex(op, &sem->value, 1, nullptr);
|
futex(FUTEX_WAKE, &sem->value, 1, nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -888,17 +888,3 @@ void srandom(unsigned seed)
|
||||||
{
|
{
|
||||||
s_random_state.seed(seed);
|
s_random_state.seed(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* initstate(unsigned seed, char* state, size_t size)
|
|
||||||
{
|
|
||||||
(void)seed;
|
|
||||||
(void)state;
|
|
||||||
(void)size;
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
char* setstate(char* state)
|
|
||||||
{
|
|
||||||
(void)state;
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue