Kernel: Fix most of mutex + block race conditions

All block functions now take an optional mutex parameter that is
atomically unlocked instead of having the user unlock it before hand.
This prevents a ton of race conditions everywhere in the code!
This commit is contained in:
Bananymous 2025-06-06 03:59:22 +03:00
parent 96d5ed9cc7
commit eecdad50a6
36 changed files with 374 additions and 322 deletions

View File

@ -182,7 +182,7 @@ namespace Kernel
private: private:
BAN::WeakPtr<SharedFileData> m_shared_region; BAN::WeakPtr<SharedFileData> m_shared_region;
Mutex m_epoll_mutex; SpinLock m_epoll_lock;
BAN::LinkedList<class Epoll*> m_epolls; BAN::LinkedList<class Epoll*> m_epolls;
friend class Epoll; friend class Epoll;
friend class FileBackedRegion; friend class FileBackedRegion;

View File

@ -29,30 +29,4 @@ namespace Kernel
Lock& m_lock; Lock& m_lock;
}; };
template<typename Lock>
class LockFreeGuard
{
BAN_NON_COPYABLE(LockFreeGuard);
BAN_NON_MOVABLE(LockFreeGuard);
public:
LockFreeGuard(Lock& lock)
: m_lock(lock)
, m_depth(lock.lock_depth())
{
for (uint32_t i = 0; i < m_depth; i++)
m_lock.unlock();
}
~LockFreeGuard()
{
for (uint32_t i = 0; i < m_depth; i++)
m_lock.lock();
}
private:
Lock& m_lock;
const uint32_t m_depth;
};
} }

View File

@ -9,7 +9,19 @@
namespace Kernel namespace Kernel
{ {
class Mutex class BaseMutex
{
public:
virtual void lock() = 0;
virtual bool try_lock() = 0;
virtual void unlock() = 0;
virtual pid_t locker() const = 0;
virtual bool is_locked() const = 0;
virtual uint32_t lock_depth() const = 0;
};
class Mutex : public BaseMutex
{ {
BAN_NON_COPYABLE(Mutex); BAN_NON_COPYABLE(Mutex);
BAN_NON_MOVABLE(Mutex); BAN_NON_MOVABLE(Mutex);
@ -17,9 +29,10 @@ namespace Kernel
public: public:
Mutex() = default; Mutex() = default;
void lock() void lock() override
{ {
const auto tid = Thread::current_tid(); const auto tid = Thread::current_tid();
ASSERT(!tid || !Thread::current().has_spinlock());
if (tid == m_locker) if (tid == m_locker)
ASSERT(m_lock_depth > 0); ASSERT(m_lock_depth > 0);
else else
@ -37,9 +50,10 @@ namespace Kernel
m_lock_depth++; m_lock_depth++;
} }
bool try_lock() bool try_lock() override
{ {
const auto tid = Thread::current_tid(); const auto tid = Thread::current_tid();
ASSERT(!tid || !Thread::current().has_spinlock());
if (tid == m_locker) if (tid == m_locker)
ASSERT(m_lock_depth > 0); ASSERT(m_lock_depth > 0);
else else
@ -55,7 +69,7 @@ namespace Kernel
return true; return true;
} }
void unlock() void unlock() override
{ {
const auto tid = Thread::current_tid(); const auto tid = Thread::current_tid();
ASSERT(m_locker == tid); ASSERT(m_locker == tid);
@ -68,16 +82,16 @@ namespace Kernel
} }
} }
pid_t locker() const { return m_locker; } pid_t locker() const override { return m_locker; }
bool is_locked() const { return m_locker != -1; } bool is_locked() const override { return m_locker != -1; }
uint32_t lock_depth() const { return m_lock_depth; } uint32_t lock_depth() const override { return m_lock_depth; }
private: private:
BAN::Atomic<pid_t> m_locker { -1 }; BAN::Atomic<pid_t> m_locker { -1 };
uint32_t m_lock_depth { 0 }; uint32_t m_lock_depth { 0 };
}; };
class PriorityMutex class PriorityMutex : public BaseMutex
{ {
BAN_NON_COPYABLE(PriorityMutex); BAN_NON_COPYABLE(PriorityMutex);
BAN_NON_MOVABLE(PriorityMutex); BAN_NON_MOVABLE(PriorityMutex);
@ -85,7 +99,7 @@ namespace Kernel
public: public:
PriorityMutex() = default; PriorityMutex() = default;
void lock() void lock() override
{ {
const auto tid = Thread::current_tid(); const auto tid = Thread::current_tid();
ASSERT(!tid || !Thread::current().has_spinlock()); ASSERT(!tid || !Thread::current().has_spinlock());
@ -110,7 +124,7 @@ namespace Kernel
m_lock_depth++; m_lock_depth++;
} }
bool try_lock() bool try_lock() override
{ {
const auto tid = Thread::current_tid(); const auto tid = Thread::current_tid();
ASSERT(!tid || !Thread::current().has_spinlock()); ASSERT(!tid || !Thread::current().has_spinlock());
@ -133,7 +147,7 @@ namespace Kernel
return true; return true;
} }
void unlock() void unlock() override
{ {
const auto tid = Thread::current_tid(); const auto tid = Thread::current_tid();
ASSERT(m_locker == tid); ASSERT(m_locker == tid);
@ -149,9 +163,9 @@ namespace Kernel
} }
} }
pid_t locker() const { return m_locker; } pid_t locker() const override { return m_locker; }
bool is_locked() const { return m_locker != -1; } bool is_locked() const override { return m_locker != -1; }
uint32_t lock_depth() const { return m_lock_depth; } uint32_t lock_depth() const override { return m_lock_depth; }
private: private:
BAN::Atomic<pid_t> m_locker { -1 }; BAN::Atomic<pid_t> m_locker { -1 };

View File

@ -24,6 +24,8 @@ namespace Kernel
void unlock(InterruptState state); void unlock(InterruptState state);
uint32_t lock_depth() const { return current_processor_has_lock(); }
bool current_processor_has_lock() const bool current_processor_has_lock() const
{ {
return m_locker.load(BAN::MemoryOrder::memory_order_relaxed) == Processor::current_id().as_u32(); return m_locker.load(BAN::MemoryOrder::memory_order_relaxed) == Processor::current_id().as_u32();
@ -72,6 +74,8 @@ namespace Kernel
Processor::set_interrupt_state(state); Processor::set_interrupt_state(state);
} }
uint32_t lock_depth() const { return m_lock_depth; }
bool current_processor_has_lock() const bool current_processor_has_lock() const
{ {
return m_locker.load(BAN::MemoryOrder::memory_order_relaxed) == Processor::current_id().as_u32(); return m_locker.load(BAN::MemoryOrder::memory_order_relaxed) == Processor::current_id().as_u32();
@ -82,6 +86,9 @@ namespace Kernel
uint32_t m_lock_depth { 0 }; uint32_t m_lock_depth { 0 };
}; };
template<typename Lock>
class SpinLockGuardAsMutex;
template<typename Lock> template<typename Lock>
class SpinLockGuard class SpinLockGuard
{ {
@ -103,6 +110,7 @@ namespace Kernel
private: private:
Lock& m_lock; Lock& m_lock;
InterruptState m_state; InterruptState m_state;
friend class SpinLockGuardAsMutex<Lock>;
}; };
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <BAN/UniqPtr.h> #include <BAN/UniqPtr.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Memory/PageTable.h> #include <kernel/Memory/PageTable.h>
#include <kernel/Memory/Types.h> #include <kernel/Memory/Types.h>
#include <kernel/ThreadBlocker.h> #include <kernel/ThreadBlocker.h>
@ -41,9 +42,9 @@ namespace Kernel
size_t virtual_page_count() const { return BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE); } size_t virtual_page_count() const { return BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE); }
size_t physical_page_count() const { return m_physical_page_count; } size_t physical_page_count() const { return m_physical_page_count; }
void pin() { m_pinned_count++; } void pin();
void unpin() { if (--m_pinned_count == 0) m_pinned_blocker.unblock(); } void unpin();
void wait_not_pinned() { while (m_pinned_count) m_pinned_blocker.block_with_timeout_ms(100); } void wait_not_pinned();
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) = 0; virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) = 0;
@ -68,6 +69,7 @@ namespace Kernel
vaddr_t m_vaddr { 0 }; vaddr_t m_vaddr { 0 };
size_t m_physical_page_count { 0 }; size_t m_physical_page_count { 0 };
Mutex m_pinned_mutex;
BAN::Atomic<size_t> m_pinned_count { 0 }; BAN::Atomic<size_t> m_pinned_count { 0 };
ThreadBlocker m_pinned_blocker; ThreadBlocker m_pinned_blocker;
}; };

View File

@ -331,7 +331,6 @@ namespace Kernel
bool m_is_userspace { false }; bool m_is_userspace { false };
SpinLock m_child_exit_lock;
BAN::Vector<ChildExitStatus> m_child_exit_statuses; BAN::Vector<ChildExitStatus> m_child_exit_statuses;
ThreadBlocker m_child_exit_blocker; ThreadBlocker m_child_exit_blocker;

View File

@ -11,6 +11,7 @@
namespace Kernel namespace Kernel
{ {
class BaseMutex;
class Thread; class Thread;
class ThreadBlocker; class ThreadBlocker;
@ -86,7 +87,7 @@ namespace Kernel
// if thread is already bound, this will never fail // if thread is already bound, this will never fail
BAN::ErrorOr<void> add_thread(Thread*); BAN::ErrorOr<void> add_thread(Thread*);
void block_current_thread(ThreadBlocker* thread_blocker, uint64_t wake_time_ns); void block_current_thread(ThreadBlocker* thread_blocker, uint64_t wake_time_ns, BaseMutex* mutex);
void unblock_thread(Thread*); void unblock_thread(Thread*);
Thread& current_thread(); Thread& current_thread();

View File

@ -58,13 +58,27 @@ namespace Kernel
bool add_signal(int signal); bool add_signal(int signal);
// blocks current thread and returns either on unblock, eintr, spuriously or after timeout // blocks current thread and returns either on unblock, eintr, spuriously or after timeout
BAN::ErrorOr<void> sleep_or_eintr_ms(uint64_t ms) { ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(ms, 1'000'000)); return sleep_or_eintr_ns(ms * 1'000'000); } // if mutex is not nullptr, it will be atomically freed before blocking and automatically locked on wake
BAN::ErrorOr<void> sleep_or_eintr_ns(uint64_t ns); BAN::ErrorOr<void> sleep_or_eintr_ns(uint64_t ns);
BAN::ErrorOr<void> block_or_eintr_indefinite(ThreadBlocker& thread_blocker); BAN::ErrorOr<void> block_or_eintr_indefinite(ThreadBlocker& thread_blocker, BaseMutex* mutex);
BAN::ErrorOr<void> block_or_eintr_or_timeout_ms(ThreadBlocker& thread_blocker, uint64_t timeout_ms, bool etimedout) { ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(timeout_ms, 1'000'000)); return block_or_eintr_or_timeout_ns(thread_blocker, timeout_ms * 1'000'000, etimedout); } BAN::ErrorOr<void> block_or_eintr_or_timeout_ns(ThreadBlocker& thread_blocker, uint64_t timeout_ns, bool etimedout, BaseMutex* mutex);
BAN::ErrorOr<void> block_or_eintr_or_waketime_ms(ThreadBlocker& thread_blocker, uint64_t wake_time_ms, bool etimedout) { ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(wake_time_ms, 1'000'000)); return block_or_eintr_or_waketime_ns(thread_blocker, wake_time_ms * 1'000'000, etimedout); } BAN::ErrorOr<void> block_or_eintr_or_waketime_ns(ThreadBlocker& thread_blocker, uint64_t wake_time_ns, bool etimedout, BaseMutex* mutex);
BAN::ErrorOr<void> block_or_eintr_or_timeout_ns(ThreadBlocker& thread_blocker, uint64_t timeout_ns, bool etimedout);
BAN::ErrorOr<void> block_or_eintr_or_waketime_ns(ThreadBlocker& thread_blocker, uint64_t wake_time_ns, bool etimedout); BAN::ErrorOr<void> sleep_or_eintr_ms(uint64_t ms)
{
ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(ms, 1'000'000));
return sleep_or_eintr_ns(ms * 1'000'000);
}
BAN::ErrorOr<void> block_or_eintr_or_timeout_ms(ThreadBlocker& thread_blocker, uint64_t timeout_ms, bool etimedout, BaseMutex* mutex)
{
ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(timeout_ms, 1'000'000));
return block_or_eintr_or_timeout_ns(thread_blocker, timeout_ms * 1'000'000, etimedout, mutex);
}
BAN::ErrorOr<void> block_or_eintr_or_waketime_ms(ThreadBlocker& thread_blocker, uint64_t wake_time_ms, bool etimedout, BaseMutex* mutex)
{
ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(wake_time_ms, 1'000'000));
return block_or_eintr_or_waketime_ns(thread_blocker, wake_time_ms * 1'000'000, etimedout, mutex);
}
pid_t tid() const { return m_tid; } pid_t tid() const { return m_tid; }

View File

@ -10,13 +10,23 @@ namespace Kernel
class ThreadBlocker class ThreadBlocker
{ {
public: public:
void block_indefinite(); void block_indefinite(BaseMutex*);
void block_with_timeout_ms(uint64_t timeout_ms) { ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(timeout_ms, 1'000'000)); return block_with_timeout_ns(timeout_ms * 1'000'000); } void block_with_timeout_ns(uint64_t timeout_ns, BaseMutex*);
void block_with_wake_time_ms(uint64_t wake_time_ms) { ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(wake_time_ms, 1'000'000)); return block_with_wake_time_ns(wake_time_ms * 1'000'000); } void block_with_wake_time_ns(uint64_t wake_time_ns, BaseMutex*);
void block_with_timeout_ns(uint64_t timeout_ns);
void block_with_wake_time_ns(uint64_t wake_time_ns);
void unblock(); void unblock();
void block_with_timeout_ms(uint64_t timeout_ms, BaseMutex* mutex)
{
ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(timeout_ms, 1'000'000));
return block_with_timeout_ns(timeout_ms * 1'000'000, mutex);
}
void block_with_wake_time_ms(uint64_t wake_time_ms, BaseMutex* mutex)
{
ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(wake_time_ms, 1'000'000));
return block_with_wake_time_ns(wake_time_ms * 1'000'000, mutex);
}
private: private:
void add_thread_to_block_queue(SchedulerQueue::Node*); void add_thread_to_block_queue(SchedulerQueue::Node*);
void remove_blocked_thread(SchedulerQueue::Node*); void remove_blocked_thread(SchedulerQueue::Node*);

View File

@ -963,7 +963,7 @@ acpi_release_global_lock:
// FIXME: this can cause missing of event if it happens between // FIXME: this can cause missing of event if it happens between
// reading the status and blocking // reading the status and blocking
m_event_thread_blocker.block_with_timeout_ms(100); m_event_thread_blocker.block_with_timeout_ms(100, nullptr);
continue; continue;
handle_event: handle_event:

View File

@ -1,5 +1,6 @@
#include <kernel/Epoll.h> #include <kernel/Epoll.h>
#include <kernel/Lock/LockGuard.h> #include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
namespace Kernel namespace Kernel
@ -45,10 +46,12 @@ namespace Kernel
TRY(inode->add_epoll(this)); TRY(inode->add_epoll(this));
it->value.add_fd(fd, event); it->value.add_fd(fd, event);
auto processing_it = m_processing_events.find(inode); SpinLockGuard _(m_ready_lock);
if (processing_it == m_processing_events.end()) auto ready_it = m_ready_events.find(inode);
processing_it = MUST(m_processing_events.insert(inode, 0)); if (ready_it == m_ready_events.end())
processing_it->value |= event.events; ready_it = MUST(m_ready_events.insert(inode, 0));
ready_it->value |= event.events;
m_thread_blocker.unblock();
return {}; return {};
} }
@ -61,10 +64,12 @@ namespace Kernel
it->value.events[fd] = event; it->value.events[fd] = event;
auto processing_it = m_processing_events.find(inode); SpinLockGuard _(m_ready_lock);
if (processing_it == m_processing_events.end()) auto ready_it = m_ready_events.find(inode);
processing_it = MUST(m_processing_events.insert(inode, 0)); if (ready_it == m_ready_events.end())
processing_it->value |= event.events; ready_it = MUST(m_ready_events.insert(inode, 0));
ready_it->value |= event.events;
m_thread_blocker.unblock();
return {}; return {};
} }
@ -196,8 +201,14 @@ namespace Kernel
const uint64_t current_ns = SystemTimer::get().ns_since_boot(); const uint64_t current_ns = SystemTimer::get().ns_since_boot();
if (current_ns >= waketime_ns) if (current_ns >= waketime_ns)
break; break;
SpinLockGuard guard(m_ready_lock);
if (!m_ready_events.empty())
continue;
SpinLockGuardAsMutex smutex(guard);
const uint64_t timeout_ns = BAN::Math::min<uint64_t>(100'000'000, waketime_ns - current_ns); const uint64_t timeout_ns = BAN::Math::min<uint64_t>(100'000'000, waketime_ns - current_ns);
TRY(Thread::current().block_or_eintr_or_timeout_ns(m_thread_blocker, timeout_ns, false)); TRY(Thread::current().block_or_eintr_or_timeout_ns(m_thread_blocker, timeout_ns, false, &smutex));
} }
return event_count; return event_count;

View File

@ -46,68 +46,66 @@ namespace Kernel
void DevFileSystem::initialize_device_updater() void DevFileSystem::initialize_device_updater()
{ {
Process::create_kernel( Process::create_kernel(
[](void*) [](void* _devfs)
{ {
auto* devfs = static_cast<DevFileSystem*>(_devfs);
while (true) while (true)
{ {
{ {
LockGuard _(s_instance->m_device_lock); LockGuard _(devfs->m_device_lock);
for (auto& device : s_instance->m_devices) for (auto& device : devfs->m_devices)
device->update(); device->update();
} }
SystemTimer::get().sleep_ms(10); SystemTimer::get().sleep_ms(10);
} }
}, nullptr }, s_instance
); );
auto* sync_process = Process::create_kernel(); auto* sync_process = Process::create_kernel();
sync_process->add_thread(MUST(Thread::create_kernel( sync_process->add_thread(MUST(Thread::create_kernel(
[](void*) [](void* _devfs)
{ {
auto* devfs = static_cast<DevFileSystem*>(_devfs);
while (true) while (true)
{ {
LockGuard _(s_instance->m_device_lock); LockGuard _(devfs->m_device_lock);
while (!s_instance->m_should_sync) while (!devfs->m_should_sync)
{ devfs->m_sync_thread_blocker.block_indefinite(&devfs->m_device_lock);
LockFreeGuard _(s_instance->m_device_lock);
s_instance->m_sync_thread_blocker.block_indefinite();
}
for (auto& device : s_instance->m_devices) for (auto& device : devfs->m_devices)
if (device->is_storage_device()) if (device->is_storage_device())
if (auto ret = static_cast<StorageDevice*>(device.ptr())->sync_disk_cache(); ret.is_error()) if (auto ret = static_cast<StorageDevice*>(device.ptr())->sync_disk_cache(); ret.is_error())
dwarnln("disk sync: {}", ret.error()); dwarnln("disk sync: {}", ret.error());
s_instance->m_should_sync = false; devfs->m_should_sync = false;
s_instance->m_sync_done.unblock(); devfs->m_sync_done.unblock();
} }
}, nullptr, sync_process }, s_instance, sync_process
))); )));
sync_process->add_thread(MUST(Kernel::Thread::create_kernel( sync_process->add_thread(MUST(Kernel::Thread::create_kernel(
[](void*) [](void* _devfs)
{ {
auto* devfs = static_cast<DevFileSystem*>(_devfs);
while (true) while (true)
{ {
SystemTimer::get().sleep_ms(10'000); SystemTimer::get().sleep_ms(10'000);
s_instance->initiate_sync(false); devfs->initiate_sync(false);
} }
}, nullptr, sync_process }, s_instance, sync_process
))); )));
sync_process->register_to_scheduler(); sync_process->register_to_scheduler();
} }
void DevFileSystem::initiate_sync(bool should_block) void DevFileSystem::initiate_sync(bool should_block)
{
{ {
LockGuard _(m_device_lock); LockGuard _(m_device_lock);
m_should_sync = true; m_should_sync = true;
m_sync_thread_blocker.unblock(); m_sync_thread_blocker.unblock();
} while (should_block && m_should_sync)
if (should_block) m_sync_done.block_indefinite(&m_device_lock);
m_sync_done.block_indefinite();
} }
void DevFileSystem::add_device(BAN::RefPtr<Device> device) void DevFileSystem::add_device(BAN::RefPtr<Device> device)

View File

@ -278,14 +278,14 @@ namespace Kernel
BAN::ErrorOr<void> Inode::add_epoll(class Epoll* epoll) BAN::ErrorOr<void> Inode::add_epoll(class Epoll* epoll)
{ {
LockGuard _(m_epoll_mutex); SpinLockGuard _(m_epoll_lock);
TRY(m_epolls.push_back(epoll)); TRY(m_epolls.push_back(epoll));
return {}; return {};
} }
void Inode::del_epoll(class Epoll* epoll) void Inode::del_epoll(class Epoll* epoll)
{ {
LockGuard _(m_epoll_mutex); SpinLockGuard _(m_epoll_lock);
for (auto it = m_epolls.begin(); it != m_epolls.end(); it++) for (auto it = m_epolls.begin(); it != m_epolls.end(); it++)
{ {
if (*it != epoll) if (*it != epoll)
@ -297,7 +297,7 @@ namespace Kernel
void Inode::epoll_notify(uint32_t event) void Inode::epoll_notify(uint32_t event)
{ {
LockGuard _(m_epoll_mutex); SpinLockGuard _(m_epoll_lock);
for (auto* epoll : m_epolls) for (auto* epoll : m_epolls)
epoll->notify(this, event); epoll->notify(this, event);
} }

View File

@ -44,6 +44,8 @@ namespace Kernel
void Pipe::on_close(int status_flags) void Pipe::on_close(int status_flags)
{ {
LockGuard _(m_mutex);
if (status_flags & O_WRONLY) if (status_flags & O_WRONLY)
{ {
auto old_writing_count = m_writing_count.fetch_sub(1); auto old_writing_count = m_writing_count.fetch_sub(1);
@ -71,8 +73,7 @@ namespace Kernel
{ {
if (m_writing_count == 0) if (m_writing_count == 0)
return 0; return 0;
LockFreeGuard lock_free(m_mutex); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false));
} }
const size_t to_copy = BAN::Math::min<size_t>(buffer.size(), m_buffer_size); const size_t to_copy = BAN::Math::min<size_t>(buffer.size(), m_buffer_size);
@ -108,8 +109,7 @@ namespace Kernel
Thread::current().add_signal(SIGPIPE); Thread::current().add_signal(SIGPIPE);
return BAN::Error::from_errno(EPIPE); return BAN::Error::from_errno(EPIPE);
} }
LockFreeGuard lock_free(m_mutex); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false));
} }
const size_t to_copy = BAN::Math::min(buffer.size(), m_buffer.size() - m_buffer_size); const size_t to_copy = BAN::Math::min(buffer.size(), m_buffer.size() - m_buffer_size);

View File

@ -1,6 +1,5 @@
#include <kernel/FS/ProcFS/FileSystem.h> #include <kernel/FS/ProcFS/FileSystem.h>
#include <kernel/FS/ProcFS/Inode.h> #include <kernel/FS/ProcFS/Inode.h>
#include <kernel/Lock/LockGuard.h>
namespace Kernel namespace Kernel
{ {

View File

@ -1,7 +1,7 @@
#include <kernel/Device/DeviceNumbers.h> #include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Input/InputDevice.h> #include <kernel/Input/InputDevice.h>
#include <kernel/Lock/LockGuard.h> #include <kernel/Lock/SpinLockAsMutex.h>
#include <LibInput/KeyEvent.h> #include <LibInput/KeyEvent.h>
#include <LibInput/MouseEvent.h> #include <LibInput/MouseEvent.h>
@ -181,23 +181,18 @@ namespace Kernel
if (buffer.size() < m_event_size) if (buffer.size() < m_event_size)
return BAN::Error::from_errno(ENOBUFS); return BAN::Error::from_errno(ENOBUFS);
auto state = m_event_lock.lock(); SpinLockGuard guard(m_event_lock);
while (m_event_count == 0) while (m_event_count == 0)
{ {
m_event_lock.unlock(state); // FIXME: should m_mutex be unlocked?
{ SpinLockGuardAsMutex smutex(guard);
LockFreeGuard _(m_mutex); TRY(Thread::current().block_or_eintr_indefinite(m_event_thread_blocker, &smutex));
TRY(Thread::current().block_or_eintr_indefinite(m_event_thread_blocker));
}
state = m_event_lock.lock();
} }
memcpy(buffer.data(), &m_event_buffer[m_event_tail * m_event_size], m_event_size); memcpy(buffer.data(), &m_event_buffer[m_event_tail * m_event_size], m_event_size);
m_event_tail = (m_event_tail + 1) % m_max_event_count; m_event_tail = (m_event_tail + 1) % m_max_event_count;
m_event_count--; m_event_count--;
m_event_lock.unlock(state);
return m_event_size; return m_event_size;
} }
@ -256,8 +251,8 @@ namespace Kernel
return bytes; return bytes;
} }
LockFreeGuard _(m_mutex); // FIXME: race condition as notify doesn't lock mutex
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker)); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
} }
} }
@ -308,8 +303,8 @@ namespace Kernel
return bytes; return bytes;
} }
LockFreeGuard _(m_mutex); // FIXME: race condition as notify doesn't lock mutex
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker)); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
} }
} }

View File

@ -1,4 +1,3 @@
#include <kernel/Lock/LockGuard.h>
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Memory/MemoryBackedRegion.h> #include <kernel/Memory/MemoryBackedRegion.h>

View File

@ -1,3 +1,4 @@
#include <kernel/Lock/LockGuard.h>
#include <kernel/Memory/MemoryRegion.h> #include <kernel/Memory/MemoryRegion.h>
namespace Kernel namespace Kernel
@ -59,4 +60,24 @@ namespace Kernel
return ret; return ret;
} }
void MemoryRegion::pin()
{
LockGuard _(m_pinned_mutex);
m_pinned_count++;
}
void MemoryRegion::unpin()
{
LockGuard _(m_pinned_mutex);
if (--m_pinned_count == 0)
m_pinned_blocker.unblock();
}
void MemoryRegion::wait_not_pinned()
{
LockGuard _(m_pinned_mutex);
while (m_pinned_count)
m_pinned_blocker.block_with_timeout_ms(100, &m_pinned_mutex);
}
} }

View File

@ -1,4 +1,3 @@
#include <kernel/Lock/LockGuard.h>
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Memory/VirtualRange.h> #include <kernel/Memory/VirtualRange.h>

View File

@ -1,3 +1,4 @@
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Networking/ARPTable.h> #include <kernel/Networking/ARPTable.h>
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
@ -158,16 +159,15 @@ namespace Kernel
for (;;) for (;;)
{ {
PendingArpPacket pending = ({ PendingArpPacket pending = ({
auto state = m_pending_lock.lock(); SpinLockGuard guard(m_pending_lock);
while (m_pending_packets.empty()) while (m_pending_packets.empty())
{ {
m_pending_lock.unlock(state); SpinLockGuardAsMutex smutex(guard);
m_pending_thread_blocker.block_with_timeout_ms(100); m_pending_thread_blocker.block_indefinite(&smutex);
state = m_pending_lock.lock();
} }
auto packet = m_pending_packets.front(); auto packet = m_pending_packets.front();
m_pending_packets.pop(); m_pending_packets.pop();
m_pending_lock.unlock(state);
packet; packet;
}); });

View File

@ -1,5 +1,6 @@
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Memory/PageTable.h> #include <kernel/Memory/PageTable.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Networking/ICMP.h> #include <kernel/Networking/ICMP.h>
#include <kernel/Networking/IPv4Layer.h> #include <kernel/Networking/IPv4Layer.h>
#include <kernel/Networking/NetworkManager.h> #include <kernel/Networking/NetworkManager.h>
@ -331,16 +332,15 @@ namespace Kernel
for (;;) for (;;)
{ {
PendingIPv4Packet pending = ({ PendingIPv4Packet pending = ({
auto state = m_pending_lock.lock(); SpinLockGuard guard(m_pending_lock);
while (m_pending_packets.empty()) while (m_pending_packets.empty())
{ {
m_pending_lock.unlock(state); SpinLockGuardAsMutex smutex(guard);
m_pending_thread_blocker.block_with_timeout_ms(100); m_pending_thread_blocker.block_indefinite(&smutex);
state = m_pending_lock.lock();
} }
auto packet = m_pending_packets.front(); auto packet = m_pending_packets.front();
m_pending_packets.pop(); m_pending_packets.pop();
m_pending_lock.unlock(state);
packet; packet;
}); });

View File

@ -1,3 +1,4 @@
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Networking/NetworkManager.h> #include <kernel/Networking/NetworkManager.h>
#include <kernel/Networking/RTL8169/Definitions.h> #include <kernel/Networking/RTL8169/Definitions.h>
#include <kernel/Networking/RTL8169/RTL8169.h> #include <kernel/Networking/RTL8169/RTL8169.h>
@ -205,13 +206,18 @@ namespace Kernel
return BAN::Error::from_errno(EADDRNOTAVAIL); return BAN::Error::from_errno(EADDRNOTAVAIL);
auto state = m_lock.lock(); auto state = m_lock.lock();
const uint32_t tx_current = m_tx_current; const uint32_t tx_current = m_tx_current;
m_tx_current = (m_tx_current + 1) % m_tx_descriptor_count; m_tx_current = (m_tx_current + 1) % m_tx_descriptor_count;
m_lock.unlock(state);
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_tx_descriptor_region->vaddr())[tx_current]; auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_tx_descriptor_region->vaddr())[tx_current];
while (descriptor.command & RTL8169_DESC_CMD_OWN) while (descriptor.command & RTL8169_DESC_CMD_OWN)
m_thread_blocker.block_with_timeout_ms(100); {
SpinLockAsMutex smutex(m_lock, state);
m_thread_blocker.block_indefinite(&smutex);
}
m_lock.unlock(state);
auto* tx_buffer = reinterpret_cast<uint8_t*>(m_tx_buffer_region->vaddr() + tx_current * buffer_size); auto* tx_buffer = reinterpret_cast<uint8_t*>(m_tx_buffer_region->vaddr() + tx_current * buffer_size);
@ -246,7 +252,10 @@ namespace Kernel
} }
if (interrupt_status & RTL8169_IR_TOK) if (interrupt_status & RTL8169_IR_TOK)
{
SpinLockGuard _(m_lock);
m_thread_blocker.unblock(); m_thread_blocker.unblock();
}
if (interrupt_status & RTL8169_IR_RER) if (interrupt_status & RTL8169_IR_RER)
dwarnln("Rx error"); dwarnln("Rx error");

View File

@ -73,10 +73,7 @@ namespace Kernel
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
while (m_pending_connections.empty()) while (m_pending_connections.empty())
{ TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
LockFreeGuard _(m_mutex);
TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false));
}
auto connection = m_pending_connections.front(); auto connection = m_pending_connections.front();
m_pending_connections.pop(); m_pending_connections.pop();
@ -111,12 +108,7 @@ namespace Kernel
const uint64_t wake_time_ms = SystemTimer::get().ms_since_boot() + 5000; const uint64_t wake_time_ms = SystemTimer::get().ms_since_boot() + 5000;
while (!return_inode->m_has_connected) while (!return_inode->m_has_connected)
{ TRY(Thread::current().block_or_eintr_or_waketime_ms(return_inode->m_thread_blocker, wake_time_ms, true, &m_mutex));
if (SystemTimer::get().ms_since_boot() >= wake_time_ms)
return BAN::Error::from_errno(ECONNABORTED);
LockFreeGuard free(m_mutex);
TRY(Thread::current().block_or_eintr_or_waketime_ms(return_inode->m_thread_blocker, wake_time_ms, true));
}
if (address) if (address)
{ {
@ -168,12 +160,7 @@ namespace Kernel
const uint64_t wake_time_ms = SystemTimer::get().ms_since_boot() + 5000; const uint64_t wake_time_ms = SystemTimer::get().ms_since_boot() + 5000;
while (!m_has_connected) while (!m_has_connected)
{ TRY(Thread::current().block_or_eintr_or_waketime_ms(m_thread_blocker, wake_time_ms, true, &m_mutex));
if (SystemTimer::get().ms_since_boot() >= wake_time_ms)
return BAN::Error::from_errno(ECONNREFUSED);
LockFreeGuard free(m_mutex);
TRY(Thread::current().block_or_eintr_or_waketime_ms(m_thread_blocker, wake_time_ms, true));
}
return {}; return {};
} }
@ -208,8 +195,7 @@ namespace Kernel
{ {
if (m_state != State::Established) if (m_state != State::Established)
return return_with_maybe_zero(); return return_with_maybe_zero();
LockFreeGuard free(m_mutex); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false));
} }
const uint32_t to_recv = BAN::Math::min<uint32_t>(buffer.size(), m_recv_window.data_size); const uint32_t to_recv = BAN::Math::min<uint32_t>(buffer.size(), m_recv_window.data_size);
@ -239,8 +225,7 @@ namespace Kernel
{ {
if (m_state != State::Established) if (m_state != State::Established)
return return_with_maybe_zero(); return return_with_maybe_zero();
LockFreeGuard free(m_mutex); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false));
} }
const size_t to_send = BAN::Math::min<size_t>(message.size(), m_send_window.buffer->size() - m_send_window.data_size); const size_t to_send = BAN::Math::min<size_t>(message.size(), m_send_window.buffer->size() - m_send_window.data_size);
@ -519,8 +504,10 @@ namespace Kernel
} }
auto socket = it->value; auto socket = it->value;
LockFreeGuard _(m_mutex); m_mutex.unlock();
socket->receive_packet(buffer, sender, sender_len); socket->receive_packet(buffer, sender, sender_len);
m_mutex.lock();
return; return;
} }
break; break;
@ -660,13 +647,12 @@ namespace Kernel
BAN::RefPtr<TCPSocket> keep_alive { this }; BAN::RefPtr<TCPSocket> keep_alive { this };
this->unref(); this->unref();
LockGuard _(m_mutex);
while (m_process) while (m_process)
{ {
const uint64_t current_ms = SystemTimer::get().ms_since_boot(); const uint64_t current_ms = SystemTimer::get().ms_since_boot();
{
LockGuard _(m_mutex);
if (m_state == State::TimeWait && current_ms >= m_time_wait_start_ms + 30'000) if (m_state == State::TimeWait && current_ms >= m_time_wait_start_ms + 30'000)
{ {
set_connection_as_closed(); set_connection_as_closed();
@ -766,10 +752,9 @@ namespace Kernel
continue; continue;
} }
}
m_thread_blocker.unblock(); m_thread_blocker.unblock();
m_thread_blocker.block_with_wake_time_ms(current_ms + retransmit_timeout_ms); m_thread_blocker.block_with_wake_time_ms(current_ms + retransmit_timeout_ms, &m_mutex);
} }
m_thread_blocker.unblock(); m_thread_blocker.unblock();

View File

@ -1,3 +1,4 @@
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Networking/UDPSocket.h> #include <kernel/Networking/UDPSocket.h>
#include <kernel/Thread.h> #include <kernel/Thread.h>
@ -93,12 +94,12 @@ namespace Kernel
} }
ASSERT(m_port != PORT_NONE); ASSERT(m_port != PORT_NONE);
auto state = m_packet_lock.lock(); SpinLockGuard guard(m_packet_lock);
while (m_packets.empty()) while (m_packets.empty())
{ {
m_packet_lock.unlock(state); SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker)); TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &smutex));
state = m_packet_lock.lock();
} }
auto packet_info = m_packets.front(); auto packet_info = m_packets.front();
@ -120,8 +121,6 @@ namespace Kernel
m_packet_total_size -= packet_info.packet_size; m_packet_total_size -= packet_info.packet_size;
m_packet_lock.unlock(state);
if (address && address_len) if (address && address_len)
{ {
if (*address_len > (socklen_t)sizeof(sockaddr_storage)) if (*address_len > (socklen_t)sizeof(sockaddr_storage))

View File

@ -1,5 +1,6 @@
#include <BAN/HashMap.h> #include <BAN/HashMap.h>
#include <kernel/FS/VirtualFileSystem.h> #include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Networking/NetworkManager.h> #include <kernel/Networking/NetworkManager.h>
#include <kernel/Networking/UNIX/Socket.h> #include <kernel/Networking/UNIX/Socket.h>
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
@ -16,6 +17,8 @@ namespace Kernel
static constexpr size_t s_packet_buffer_size = 10 * PAGE_SIZE; static constexpr size_t s_packet_buffer_size = 10 * PAGE_SIZE;
// FIXME: why is this using spinlocks instead of mutexes??
BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> UnixDomainSocket::create(Socket::Type socket_type, const Socket::Info& info) BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> UnixDomainSocket::create(Socket::Type socket_type, const Socket::Info& info)
{ {
auto socket = TRY(BAN::RefPtr<UnixDomainSocket>::create(socket_type, info)); auto socket = TRY(BAN::RefPtr<UnixDomainSocket>::create(socket_type, info));
@ -91,13 +94,16 @@ namespace Kernel
if (!connection_info.listening) if (!connection_info.listening)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
while (connection_info.pending_connections.empty())
TRY(Thread::current().block_or_eintr_indefinite(connection_info.pending_thread_blocker));
BAN::RefPtr<UnixDomainSocket> pending; BAN::RefPtr<UnixDomainSocket> pending;
{ {
SpinLockGuard _(connection_info.pending_lock); SpinLockGuard guard(connection_info.pending_lock);
SpinLockGuardAsMutex smutex(guard);
while (connection_info.pending_connections.empty())
TRY(Thread::current().block_or_eintr_indefinite(connection_info.pending_thread_blocker, &smutex));
pending = connection_info.pending_connections.front(); pending = connection_info.pending_connections.front();
connection_info.pending_connections.pop(); connection_info.pending_connections.pop();
connection_info.pending_thread_blocker.unblock(); connection_info.pending_thread_blocker.unblock();
@ -176,16 +182,18 @@ namespace Kernel
for (;;) for (;;)
{ {
auto& target_info = target->m_info.get<ConnectionInfo>(); auto& target_info = target->m_info.get<ConnectionInfo>();
{
SpinLockGuard _(target_info.pending_lock); SpinLockGuard guard(target_info.pending_lock);
if (target_info.pending_connections.size() < target_info.pending_connections.capacity()) if (target_info.pending_connections.size() < target_info.pending_connections.capacity())
{ {
MUST(target_info.pending_connections.push(this)); MUST(target_info.pending_connections.push(this));
target_info.pending_thread_blocker.unblock(); target_info.pending_thread_blocker.unblock();
break; break;
} }
}
TRY(Thread::current().block_or_eintr_indefinite(target_info.pending_thread_blocker)); SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_indefinite(target_info.pending_thread_blocker, &smutex));
} }
target->epoll_notify(EPOLLIN); target->epoll_notify(EPOLLIN);
@ -269,9 +277,8 @@ namespace Kernel
auto state = m_packet_lock.lock(); auto state = m_packet_lock.lock();
while (m_packet_sizes.full() || m_packet_size_total + packet.size() > s_packet_buffer_size) while (m_packet_sizes.full() || m_packet_size_total + packet.size() > s_packet_buffer_size)
{ {
m_packet_lock.unlock(state); SpinLockAsMutex smutex(m_packet_lock, state);
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker)); TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &smutex));
state = m_packet_lock.lock();
} }
uint8_t* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr() + m_packet_size_total); uint8_t* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr() + m_packet_size_total);
@ -405,9 +412,8 @@ namespace Kernel
} }
} }
m_packet_lock.unlock(state); SpinLockAsMutex smutex(m_packet_lock, state);
TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker)); TRY(Thread::current().block_or_eintr_indefinite(m_packet_thread_blocker, &smutex));
state = m_packet_lock.lock();
} }
uint8_t* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr()); uint8_t* packet_buffer = reinterpret_cast<uint8_t*>(m_packet_buffer->vaddr());

View File

@ -279,6 +279,8 @@ namespace Kernel
if (parent.pid() != m_parent) if (parent.pid() != m_parent)
return BAN::Iteration::Continue; return BAN::Iteration::Continue;
LockGuard _(parent.m_process_lock);
for (auto& child : parent.m_child_exit_statuses) for (auto& child : parent.m_child_exit_statuses)
{ {
if (child.pid != pid()) if (child.pid != pid())
@ -767,13 +769,13 @@ namespace Kernel
return child.pid == pid; return child.pid == pid;
}; };
LockGuard _(m_process_lock);
for (;;) for (;;)
{ {
pid_t exited_pid = 0; pid_t exited_pid = 0;
int exit_code = 0; int exit_code = 0;
{ {
SpinLockGuard _(m_child_exit_lock);
bool found = false; bool found = false;
for (auto& child : m_child_exit_statuses) for (auto& child : m_child_exit_statuses)
{ {
@ -796,7 +798,6 @@ namespace Kernel
{ {
if (stat_loc) if (stat_loc)
{ {
LockGuard _(m_process_lock);
TRY(validate_pointer_access(stat_loc, sizeof(stat_loc), true)); TRY(validate_pointer_access(stat_loc, sizeof(stat_loc), true));
*stat_loc = exit_code; *stat_loc = exit_code;
} }
@ -810,7 +811,7 @@ namespace Kernel
if (options & WNOHANG) if (options & WNOHANG)
return 0; return 0;
m_child_exit_blocker.block_indefinite(); m_child_exit_blocker.block_indefinite(&m_process_lock);
} }
} }
@ -2609,11 +2610,7 @@ namespace Kernel
for (;;) for (;;)
{ {
{ TRY(Thread::current().block_or_eintr_indefinite(m_pthread_exit_blocker, &m_process_lock));
LockFreeGuard _(m_process_lock);
m_pthread_exit_blocker.block_with_timeout_ms(100);
}
if (wait_thread()) if (wait_thread())
return 0; return 0;
} }

View File

@ -1,6 +1,7 @@
#include <BAN/Optional.h> #include <BAN/Optional.h>
#include <BAN/Sort.h> #include <BAN/Sort.h>
#include <kernel/InterruptController.h> #include <kernel/InterruptController.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
#include <kernel/Thread.h> #include <kernel/Thread.h>
@ -599,7 +600,7 @@ namespace Kernel
return {}; return {};
} }
void Scheduler::block_current_thread(ThreadBlocker* blocker, uint64_t wake_time_ns) void Scheduler::block_current_thread(ThreadBlocker* blocker, uint64_t wake_time_ns, BaseMutex* mutex)
{ {
auto state = Processor::get_interrupt_state(); auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled); Processor::set_interrupt_state(InterruptState::Disabled);
@ -612,9 +613,23 @@ namespace Kernel
if (blocker) if (blocker)
blocker->add_thread_to_block_queue(m_current); blocker->add_thread_to_block_queue(m_current);
update_most_loaded_node_queue(m_current, &m_block_queue); update_most_loaded_node_queue(m_current, &m_block_queue);
uint32_t lock_depth = 0;
if (mutex != nullptr)
{
ASSERT(mutex->is_locked() && mutex->locker() == m_current->thread->tid());
lock_depth = mutex->lock_depth();
}
for (uint32_t i = 0; i < lock_depth; i++)
mutex->unlock();
Processor::yield(); Processor::yield();
Processor::set_interrupt_state(state); Processor::set_interrupt_state(state);
for (uint32_t i = 0; i < lock_depth; i++)
mutex->lock();
} }
void Scheduler::unblock_thread(Thread* thread) void Scheduler::unblock_thread(Thread* thread)

View File

@ -1,5 +1,4 @@
#include <kernel/BootInfo.h> #include <kernel/BootInfo.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Memory/PageTable.h> #include <kernel/Memory/PageTable.h>
#include <kernel/Storage/DiskCache.h> #include <kernel/Storage/DiskCache.h>

View File

@ -1,4 +1,4 @@
#include <kernel/Lock/LockGuard.h> #include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Storage/NVMe/Queue.h> #include <kernel/Storage/NVMe/Queue.h>
#include <kernel/Thread.h> #include <kernel/Thread.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
@ -72,7 +72,7 @@ namespace Kernel
// scheduler has put the current thread blocking. // scheduler has put the current thread blocking.
// EINTR should also be handled here. // EINTR should also be handled here.
while (!(m_done_mask & cid_mask) && SystemTimer::get().ms_since_boot() < start_time_ms + s_nvme_command_timeout_ms) while (!(m_done_mask & cid_mask) && SystemTimer::get().ms_since_boot() < start_time_ms + s_nvme_command_timeout_ms)
m_thread_blocker.block_with_wake_time_ms(start_time_ms + s_nvme_command_timeout_ms); m_thread_blocker.block_with_wake_time_ms(start_time_ms + s_nvme_command_timeout_ms, nullptr);
if (m_done_mask & cid_mask) if (m_done_mask & cid_mask)
{ {
@ -87,12 +87,12 @@ namespace Kernel
uint16_t NVMeQueue::reserve_cid() uint16_t NVMeQueue::reserve_cid()
{ {
auto state = m_lock.lock(); SpinLockGuard guard(m_lock);
while (~m_used_mask == 0) while (~m_used_mask == 0)
{ {
m_lock.unlock(state); SpinLockGuardAsMutex smutex(guard);
m_thread_blocker.block_with_timeout_ms(s_nvme_command_timeout_ms); m_thread_blocker.block_with_timeout_ms(s_nvme_command_timeout_ms, &smutex);
state = m_lock.lock();
} }
uint16_t cid = 0; uint16_t cid = 0;
@ -104,7 +104,6 @@ namespace Kernel
m_used_mask |= (size_t)1 << cid; m_used_mask |= (size_t)1 << cid;
m_lock.unlock(state);
return cid; return cid;
} }

View File

@ -1,5 +1,6 @@
#include <kernel/Device/DeviceNumbers.h> #include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Terminal/PseudoTerminal.h> #include <kernel/Terminal/PseudoTerminal.h>
#include <BAN/ScopeGuard.h> #include <BAN/ScopeGuard.h>
@ -87,7 +88,6 @@ namespace Kernel
} }
bool PseudoTerminalMaster::putchar(uint8_t ch) bool PseudoTerminalMaster::putchar(uint8_t ch)
{
{ {
SpinLockGuard _(m_buffer_lock); SpinLockGuard _(m_buffer_lock);
@ -98,7 +98,6 @@ namespace Kernel
m_buffer_size++; m_buffer_size++;
m_buffer_blocker.unblock(); m_buffer_blocker.unblock();
}
epoll_notify(EPOLLIN); epoll_notify(EPOLLIN);
@ -107,13 +106,12 @@ namespace Kernel
BAN::ErrorOr<size_t> PseudoTerminalMaster::read_impl(off_t, BAN::ByteSpan buffer) BAN::ErrorOr<size_t> PseudoTerminalMaster::read_impl(off_t, BAN::ByteSpan buffer)
{ {
auto state = m_buffer_lock.lock(); SpinLockGuard guard(m_buffer_lock);
while (m_buffer_size == 0) while (m_buffer_size == 0)
{ {
m_buffer_lock.unlock(state); SpinLockGuardAsMutex smutex(guard);
TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker)); TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker, &smutex));
m_buffer_lock.lock();
} }
const size_t to_copy = BAN::Math::min(buffer.size(), m_buffer_size); const size_t to_copy = BAN::Math::min(buffer.size(), m_buffer_size);
@ -132,8 +130,6 @@ namespace Kernel
m_buffer_size -= to_copy; m_buffer_size -= to_copy;
m_buffer_tail = (m_buffer_tail + to_copy) % m_buffer->size(); m_buffer_tail = (m_buffer_tail + to_copy) % m_buffer->size();
m_buffer_lock.unlock(state);
epoll_notify(EPOLLOUT); epoll_notify(EPOLLOUT);
return to_copy; return to_copy;

View File

@ -92,6 +92,8 @@ namespace Kernel
if (flags & ~(TTY_FLAG_ENABLE_INPUT | TTY_FLAG_ENABLE_OUTPUT)) if (flags & ~(TTY_FLAG_ENABLE_INPUT | TTY_FLAG_ENABLE_OUTPUT))
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
LockGuard _(m_mutex);
switch (command) switch (command)
{ {
case TTY_CMD_SET: case TTY_CMD_SET:
@ -129,12 +131,16 @@ namespace Kernel
while (true) while (true)
{ {
{
LockGuard _(TTY::current()->m_mutex);
while (!TTY::current()->m_tty_ctrl.receive_input) while (!TTY::current()->m_tty_ctrl.receive_input)
TTY::current()->m_tty_ctrl.thread_blocker.block_indefinite(); TTY::current()->m_tty_ctrl.thread_blocker.block_indefinite(&TTY::current()->m_mutex);
}
while (TTY::current()->m_tty_ctrl.receive_input) while (TTY::current()->m_tty_ctrl.receive_input)
{ {
LockGuard _(keyboard_inode->m_mutex); LockGuard _(keyboard_inode->m_mutex);
if (!keyboard_inode->can_read()) if (!keyboard_inode->can_read())
{ {
SystemTimer::get().sleep_ms(1); SystemTimer::get().sleep_ms(1);
@ -395,10 +401,7 @@ namespace Kernel
BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer) BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer)
{ {
while (!m_output.flush) while (!m_output.flush)
{ TRY(Thread::current().block_or_eintr_indefinite(m_output.thread_blocker, &m_mutex));
LockFreeGuard _(m_mutex);
TRY(Thread::current().block_or_eintr_indefinite(m_output.thread_blocker));
}
if (m_output.bytes == 0) if (m_output.bytes == 0)
{ {

View File

@ -581,27 +581,27 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<void> Thread::block_or_eintr_indefinite(ThreadBlocker& thread_blocker) BAN::ErrorOr<void> Thread::block_or_eintr_indefinite(ThreadBlocker& thread_blocker, BaseMutex* mutex)
{ {
if (is_interrupted_by_signal()) if (is_interrupted_by_signal())
return BAN::Error::from_errno(EINTR); return BAN::Error::from_errno(EINTR);
thread_blocker.block_indefinite(); thread_blocker.block_indefinite(mutex);
if (is_interrupted_by_signal()) if (is_interrupted_by_signal())
return BAN::Error::from_errno(EINTR); return BAN::Error::from_errno(EINTR);
return {}; return {};
} }
BAN::ErrorOr<void> Thread::block_or_eintr_or_timeout_ns(ThreadBlocker& thread_blocker, uint64_t timeout_ns, bool etimedout) BAN::ErrorOr<void> Thread::block_or_eintr_or_timeout_ns(ThreadBlocker& thread_blocker, uint64_t timeout_ns, bool etimedout, BaseMutex* mutex)
{ {
const uint64_t wake_time_ns = SystemTimer::get().ns_since_boot() + timeout_ns; const uint64_t wake_time_ns = SystemTimer::get().ns_since_boot() + timeout_ns;
return block_or_eintr_or_waketime_ns(thread_blocker, wake_time_ns, etimedout); return block_or_eintr_or_waketime_ns(thread_blocker, wake_time_ns, etimedout, mutex);
} }
BAN::ErrorOr<void> Thread::block_or_eintr_or_waketime_ns(ThreadBlocker& thread_blocker, uint64_t wake_time_ns, bool etimedout) BAN::ErrorOr<void> Thread::block_or_eintr_or_waketime_ns(ThreadBlocker& thread_blocker, uint64_t wake_time_ns, bool etimedout, BaseMutex* mutex)
{ {
if (is_interrupted_by_signal()) if (is_interrupted_by_signal())
return BAN::Error::from_errno(EINTR); return BAN::Error::from_errno(EINTR);
thread_blocker.block_with_wake_time_ns(wake_time_ns); thread_blocker.block_with_wake_time_ns(wake_time_ns, mutex);
if (is_interrupted_by_signal()) if (is_interrupted_by_signal())
return BAN::Error::from_errno(EINTR); return BAN::Error::from_errno(EINTR);
if (etimedout && SystemTimer::get().ms_since_boot() >= wake_time_ns) if (etimedout && SystemTimer::get().ms_since_boot() >= wake_time_ns)

View File

@ -5,19 +5,19 @@
namespace Kernel namespace Kernel
{ {
void ThreadBlocker::block_indefinite() void ThreadBlocker::block_indefinite(BaseMutex* mutex)
{ {
Processor::scheduler().block_current_thread(this, static_cast<uint64_t>(-1)); Processor::scheduler().block_current_thread(this, static_cast<uint64_t>(-1), mutex);
} }
void ThreadBlocker::block_with_timeout_ns(uint64_t timeout_ns) void ThreadBlocker::block_with_timeout_ns(uint64_t timeout_ns, BaseMutex* mutex)
{ {
Processor::scheduler().block_current_thread(this, SystemTimer::get().ns_since_boot() + timeout_ns); Processor::scheduler().block_current_thread(this, SystemTimer::get().ns_since_boot() + timeout_ns, mutex);
} }
void ThreadBlocker::block_with_wake_time_ns(uint64_t wake_time_ns) void ThreadBlocker::block_with_wake_time_ns(uint64_t wake_time_ns, BaseMutex* mutex)
{ {
Processor::scheduler().block_current_thread(this, wake_time_ns); Processor::scheduler().block_current_thread(this, wake_time_ns, mutex);
} }
void ThreadBlocker::unblock() void ThreadBlocker::unblock()

View File

@ -83,9 +83,7 @@ namespace Kernel
{ {
if (ns == 0) if (ns == 0)
return; return;
Processor::scheduler().block_current_thread(nullptr, ns_since_boot() + ns, nullptr);
const uint64_t wake_time_ns = ns_since_boot() + ns;
Processor::scheduler().block_current_thread(nullptr, wake_time_ns);
} }
timespec SystemTimer::real_time() const timespec SystemTimer::real_time() const

View File

@ -269,7 +269,8 @@ namespace Kernel
m_is_init_done = true; m_is_init_done = true;
} }
m_changed_port_blocker.block_with_timeout_ms(100); // FIXME: race condition
m_changed_port_blocker.block_with_timeout_ms(100, nullptr);
continue; continue;
} }

View File

@ -322,7 +322,8 @@ namespace Kernel
m_ports_initialized = true; m_ports_initialized = true;
} }
m_port_thread_blocker.block_with_timeout_ms(100); // FIXME: prevent race condition
m_port_thread_blocker.block_with_timeout_ms(100, nullptr);
expected = true; expected = true;
} }
} }