Compare commits
4 Commits
12489a4c6b
...
ed82a18e2a
| Author | SHA1 | Date |
|---|---|---|
|
|
ed82a18e2a | |
|
|
2961a49dc7 | |
|
|
5c9151d3e9 | |
|
|
90deb9fb43 |
|
|
@ -9,29 +9,35 @@
|
|||
#include <BAN/Formatter.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define __debug_putchar [](int c) { putc(c, stddbg); }
|
||||
#define __debug_putchar [](int c) { putc_unlocked(c, stddbg); }
|
||||
|
||||
#define dprintln(...) \
|
||||
do { \
|
||||
flockfile(stddbg); \
|
||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::print(__debug_putchar,"\n"); \
|
||||
fflush(stddbg); \
|
||||
funlockfile(stddbg); \
|
||||
} while (false)
|
||||
|
||||
#define dwarnln(...) \
|
||||
do { \
|
||||
flockfile(stddbg); \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
|
||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
||||
fflush(stddbg); \
|
||||
funlockfile(stddbg); \
|
||||
} while(false)
|
||||
|
||||
#define derrorln(...) \
|
||||
do { \
|
||||
flockfile(stddbg); \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
|
||||
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
|
||||
fflush(stddbg); \
|
||||
funlockfile(stddbg); \
|
||||
} while(false)
|
||||
|
||||
#define dprintln_if(cond, ...) \
|
||||
|
|
|
|||
|
|
@ -28,36 +28,28 @@ namespace Kernel
|
|||
BAN_NON_COPYABLE(BlockBufferWrapper);
|
||||
|
||||
public:
|
||||
BlockBufferWrapper(BAN::Span<uint8_t> buffer, bool* used, Mutex* mutex, ThreadBlocker* blocker)
|
||||
BlockBufferWrapper(BAN::Span<uint8_t> buffer, void (*callback)(void*, const uint8_t*), void* argument)
|
||||
: m_buffer(buffer)
|
||||
, m_used(used)
|
||||
, m_mutex(mutex)
|
||||
, m_blocker(blocker)
|
||||
{
|
||||
ASSERT(m_used && *m_used);
|
||||
}
|
||||
, m_callback(callback)
|
||||
, m_argument(argument)
|
||||
{ }
|
||||
BlockBufferWrapper(BlockBufferWrapper&& other) { *this = BAN::move(other); }
|
||||
~BlockBufferWrapper()
|
||||
{
|
||||
if (m_used == nullptr)
|
||||
if (m_callback == nullptr)
|
||||
return;
|
||||
m_mutex->lock();
|
||||
*m_used = false;
|
||||
m_blocker->unblock();
|
||||
m_mutex->unlock();
|
||||
m_callback(m_argument, m_buffer.data());
|
||||
}
|
||||
|
||||
BlockBufferWrapper& operator=(BlockBufferWrapper&& other)
|
||||
{
|
||||
this->m_buffer = other.m_buffer;
|
||||
this->m_used = other.m_used;
|
||||
this->m_mutex = other.m_mutex;
|
||||
this->m_blocker = other.m_blocker;
|
||||
this->m_callback = other.m_callback;
|
||||
this->m_argument = other.m_argument;
|
||||
|
||||
other.m_buffer = {};
|
||||
other.m_used = nullptr;
|
||||
other.m_mutex = nullptr;
|
||||
other.m_blocker = nullptr;
|
||||
other.m_callback = nullptr;
|
||||
other.m_argument = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -75,9 +67,8 @@ namespace Kernel
|
|||
|
||||
private:
|
||||
BAN::Span<uint8_t> m_buffer;
|
||||
bool* m_used;
|
||||
Mutex* m_mutex;
|
||||
ThreadBlocker* m_blocker;
|
||||
void (*m_callback)(void*, const uint8_t*);
|
||||
void* m_argument;
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
@ -130,6 +121,9 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> initialize(size_t block_size);
|
||||
|
||||
private:
|
||||
void destroy_callback(const uint8_t* buffer_ptr);
|
||||
|
||||
private:
|
||||
struct BlockBuffer
|
||||
{
|
||||
|
|
@ -137,10 +131,20 @@ namespace Kernel
|
|||
bool used { false };
|
||||
};
|
||||
|
||||
struct ThreadInfo
|
||||
{
|
||||
pid_t tid { 0 };
|
||||
size_t buffers { 0 };
|
||||
};
|
||||
|
||||
private:
|
||||
static constexpr size_t max_threads = 8;
|
||||
static constexpr size_t max_buffers_per_thread = 6;
|
||||
|
||||
Mutex m_buffer_mutex;
|
||||
ThreadBlocker m_buffer_blocker;
|
||||
BAN::Array<BlockBuffer, 16> m_buffers;
|
||||
BAN::Array<BlockBuffer, max_threads * max_buffers_per_thread> m_buffers;
|
||||
BAN::Array<ThreadInfo, max_threads> m_thread_infos;
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -346,6 +346,19 @@ namespace Kernel
|
|||
|
||||
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;
|
||||
|
||||
struct pthread_info_t
|
||||
|
|
|
|||
|
|
@ -532,22 +532,88 @@ namespace Kernel
|
|||
};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Ext2FS::BlockBufferWrapper> Ext2FS::BlockBufferManager::get_buffer()
|
||||
void Ext2FS::BlockBufferManager::destroy_callback(const uint8_t* buffer_ptr)
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
|
||||
LockGuard _(m_buffer_mutex);
|
||||
|
||||
for (;;)
|
||||
for (auto& buffer : m_buffers)
|
||||
{
|
||||
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()
|
||||
{
|
||||
const auto tid = Thread::current_tid();
|
||||
ASSERT(tid);
|
||||
|
||||
LockGuard _(m_buffer_mutex);
|
||||
|
||||
ThreadInfo* thread_info = nullptr;
|
||||
|
||||
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 (buffer.used)
|
||||
if (info.tid != 0)
|
||||
continue;
|
||||
buffer.used = true;
|
||||
return Ext2FS::BlockBufferWrapper(buffer.buffer.span(), &buffer.used, &m_buffer_mutex, &m_buffer_blocker);
|
||||
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)
|
||||
{
|
||||
if (buffer.used)
|
||||
continue;
|
||||
buffer.used = true;
|
||||
return Ext2FS::BlockBufferWrapper {
|
||||
buffer.buffer.span(),
|
||||
[](void* self, const uint8_t* buffer) { static_cast<BlockBufferManager*>(self)->destroy_callback(buffer); },
|
||||
this
|
||||
};
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2FS::BlockBufferManager::initialize(size_t block_size)
|
||||
|
|
|
|||
|
|
@ -38,14 +38,8 @@ namespace Kernel
|
|||
static BAN::Vector<Process*> s_processes;
|
||||
static RecursiveSpinLock s_process_lock;
|
||||
|
||||
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<Process::futex_t>> Process::s_futexes;
|
||||
Mutex Process::s_futex_lock;
|
||||
|
||||
static void for_each_process(const BAN::Function<BAN::Iteration(Process&)>& callback)
|
||||
{
|
||||
|
|
@ -3107,18 +3101,52 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
const bool is_realtime = (op & FUTEX_REALTIME);
|
||||
const bool is_private = (op & FUTEX_PRIVATE);
|
||||
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));
|
||||
BAN::ScopeGuard pin_guard([&] { if (buffer_region) buffer_region->unpin(); });
|
||||
|
||||
const paddr_t paddr = m_page_table->physical_address_of(vaddr & PAGE_ADDR_MASK) | (vaddr & ~PAGE_ADDR_MASK);
|
||||
ASSERT(paddr != 0);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case FUTEX_WAIT:
|
||||
break;
|
||||
case FUTEX_WAKE:
|
||||
abstime = nullptr;
|
||||
break;
|
||||
default:
|
||||
return BAN::Error::from_errno(ENOSYS);
|
||||
}
|
||||
|
||||
const uint64_t wake_time_ns =
|
||||
TRY([abstime, is_realtime, this]() -> BAN::ErrorOr<uint64_t>
|
||||
{
|
||||
if (abstime == nullptr)
|
||||
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));
|
||||
return abstime->tv_sec * 1'000'000'000 + abstime->tv_nsec;
|
||||
}());
|
||||
if (!is_realtime)
|
||||
return abs_ns;
|
||||
const auto realtime = SystemTimer::get().real_time();
|
||||
const uint64_t real_ns = realtime.tv_sec * 1'000'000'000 + realtime.tv_nsec;
|
||||
if (abs_ns <= real_ns)
|
||||
return BAN::Error::from_errno(ETIMEDOUT);
|
||||
return SystemTimer::get().ns_since_boot() + (abs_ns - real_ns);
|
||||
}());
|
||||
|
||||
auto& futex_lock = is_private ? m_futex_lock : s_futex_lock;
|
||||
auto& futexes = is_private ? m_futexes : s_futexes;
|
||||
|
||||
LockGuard _(futex_lock);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case FUTEX_WAIT:
|
||||
|
|
@ -3126,36 +3154,20 @@ namespace Kernel
|
|||
if (BAN::atomic_load(*addr) != val)
|
||||
return BAN::Error::from_errno(EAGAIN);
|
||||
|
||||
const uint64_t wake_time_ns =
|
||||
TRY([abstime, is_realtime, this]() -> BAN::ErrorOr<uint64_t>
|
||||
{
|
||||
if (abstime == nullptr)
|
||||
return BAN::numeric_limits<uint64_t>::max();
|
||||
TRY(validate_pointer_access(abstime, sizeof(*abstime), false));
|
||||
const uint64_t abs_ns = abstime->tv_sec * 1'000'000'000 + abstime->tv_nsec;
|
||||
if (!is_realtime)
|
||||
return abs_ns;
|
||||
const auto realtime = SystemTimer::get().real_time();
|
||||
const uint64_t real_ns = realtime.tv_sec * 1'000'000'000 + realtime.tv_nsec;
|
||||
if (abs_ns <= real_ns)
|
||||
return BAN::Error::from_errno(ETIMEDOUT);
|
||||
return SystemTimer::get().ns_since_boot() + (abs_ns - real_ns);
|
||||
}());
|
||||
|
||||
auto it = s_futexes.find(paddr);
|
||||
if (it == s_futexes.end())
|
||||
it = TRY(s_futexes.emplace(paddr, TRY(BAN::UniqPtr<futex_t>::create())));
|
||||
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->waiters++;
|
||||
BAN::ScopeGuard _([futex, paddr] {
|
||||
BAN::ScopeGuard _([&futexes, futex, paddr] {
|
||||
if (--futex->waiters == 0)
|
||||
s_futexes.remove(paddr);
|
||||
futexes.remove(paddr);
|
||||
});
|
||||
|
||||
for (;;)
|
||||
{
|
||||
TRY(Thread::current().block_or_eintr_or_waketime_ns(futex->blocker, wake_time_ns, true, &s_futex_lock));
|
||||
TRY(Thread::current().block_or_eintr_or_waketime_ns(futex->blocker, wake_time_ns, true, &futex_lock));
|
||||
if (BAN::atomic_load(*addr) == val || futex->to_wakeup == 0)
|
||||
continue;
|
||||
futex->to_wakeup--;
|
||||
|
|
@ -3164,8 +3176,8 @@ namespace Kernel
|
|||
}
|
||||
case FUTEX_WAKE:
|
||||
{
|
||||
auto it = s_futexes.find(paddr);
|
||||
if (it == s_futexes.end())
|
||||
auto it = futexes.find(paddr);
|
||||
if (it == futexes.end())
|
||||
return 0;
|
||||
futex_t* const futex = it->value.ptr();
|
||||
|
||||
|
|
@ -3178,8 +3190,6 @@ namespace Kernel
|
|||
futex->blocker.unblock();
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return BAN::Error::from_errno(ENOSYS);
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
|
|
|
|||
|
|
@ -884,9 +884,11 @@ int pthread_mutex_unlock(pthread_mutex_t* mutex)
|
|||
mutex->lock_depth--;
|
||||
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);
|
||||
if (BAN::atomic_load(mutex->waiters))
|
||||
futex(FUTEX_WAKE, &mutex->futex, 1, nullptr);
|
||||
futex(op, &mutex->futex, 1, nullptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ int sem_getvalue(sem_t* __restrict sem, int* __restrict sval)
|
|||
int sem_post(sem_t* sem)
|
||||
{
|
||||
const auto old = BAN::atomic_fetch_add(sem->value, 1);
|
||||
const int op = FUTEX_WAKE | (sem->shared ? 0 : FUTEX_PRIVATE);
|
||||
if (old == 0)
|
||||
futex(FUTEX_WAKE, &sem->value, 1, nullptr);
|
||||
futex(op, &sem->value, 1, nullptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -888,3 +888,17 @@ void srandom(unsigned 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