This moves locking to the inodes themselves which allows reducing lock times significantly. Main inodes (ext2 and tmpfs) still do contain a single big mutex that gets locked during operations but now we have the architecture to optimize these.
64 lines
1.5 KiB
C++
64 lines
1.5 KiB
C++
#include <kernel/FS/EventFD.h>
|
|
#include <kernel/Lock/LockGuard.h>
|
|
|
|
#include <sys/epoll.h>
|
|
|
|
namespace Kernel
|
|
{
|
|
|
|
BAN::ErrorOr<BAN::RefPtr<Inode>> EventFD::create(uint64_t initval, bool semaphore)
|
|
{
|
|
auto* eventfd_ptr = new EventFD(initval, semaphore);
|
|
if (eventfd_ptr == nullptr)
|
|
return BAN::Error::from_errno(ENOMEM);
|
|
return BAN::RefPtr<Inode>(BAN::RefPtr<EventFD>::adopt(eventfd_ptr));
|
|
}
|
|
|
|
BAN::ErrorOr<size_t> EventFD::read_impl(off_t, BAN::ByteSpan buffer)
|
|
{
|
|
if (buffer.size() < sizeof(uint64_t))
|
|
return BAN::Error::from_errno(EINVAL);
|
|
|
|
LockGuard _(m_mutex);
|
|
|
|
while (m_value == 0)
|
|
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
|
|
|
|
const uint64_t read_value = m_is_semaphore ? 1 : m_value.load();
|
|
m_value -= read_value;
|
|
|
|
buffer.as<uint64_t>() = read_value;
|
|
|
|
epoll_notify(EPOLLOUT);
|
|
|
|
m_thread_blocker.unblock();
|
|
|
|
return sizeof(uint64_t);
|
|
}
|
|
|
|
BAN::ErrorOr<size_t> EventFD::write_impl(off_t, BAN::ConstByteSpan buffer)
|
|
{
|
|
if (buffer.size() < sizeof(uint64_t))
|
|
return BAN::Error::from_errno(EINVAL);
|
|
|
|
const uint64_t write_value = buffer.as<const uint64_t>();
|
|
if (write_value == UINT64_MAX)
|
|
return BAN::Error::from_errno(EINVAL);
|
|
|
|
LockGuard _(m_mutex);
|
|
|
|
while (m_value + write_value < m_value)
|
|
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
|
|
|
|
m_value += write_value;
|
|
|
|
if (m_value > 0)
|
|
epoll_notify(EPOLLIN);
|
|
|
|
m_thread_blocker.unblock();
|
|
|
|
return sizeof(uint64_t);
|
|
}
|
|
|
|
}
|