Kernel: Fix epoll deadlock
If epoll_wait and epoll_notify were called at the same time, there was a possible deadlock when epoll was confirming the event from the inode
This commit is contained in:
parent
1bd454b8fd
commit
9f4b451501
|
@ -184,6 +184,7 @@ namespace Kernel
|
||||||
BAN::WeakPtr<SharedFileData> m_shared_region;
|
BAN::WeakPtr<SharedFileData> m_shared_region;
|
||||||
Mutex m_epoll_mutex;
|
Mutex m_epoll_mutex;
|
||||||
BAN::LinkedList<class Epoll*> m_epolls;
|
BAN::LinkedList<class Epoll*> m_epolls;
|
||||||
|
friend class Epoll;
|
||||||
friend class FileBackedRegion;
|
friend class FileBackedRegion;
|
||||||
friend class OpenFileDescriptorSet;
|
friend class OpenFileDescriptorSet;
|
||||||
friend class SharedFileData;
|
friend class SharedFileData;
|
||||||
|
|
|
@ -60,6 +60,8 @@ namespace Kernel
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
bool failed_lock = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
for (auto it = m_ready_events.begin(); it != m_ready_events.end() && count < event_span.size();)
|
for (auto it = m_ready_events.begin(); it != m_ready_events.end() && count < event_span.size();)
|
||||||
|
@ -70,6 +72,14 @@ namespace Kernel
|
||||||
const uint32_t listen_mask = (listen.events & (EPOLLIN | EPOLLOUT)) | EPOLLERR | EPOLLHUP;
|
const uint32_t listen_mask = (listen.events & (EPOLLIN | EPOLLOUT)) | EPOLLERR | EPOLLHUP;
|
||||||
|
|
||||||
events &= listen_mask;
|
events &= listen_mask;
|
||||||
|
|
||||||
|
// This prevents a possible deadlock
|
||||||
|
if (!inode->m_mutex.try_lock())
|
||||||
|
{
|
||||||
|
failed_lock = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECK_EVENT_BIT(mask, func) \
|
#define CHECK_EVENT_BIT(mask, func) \
|
||||||
if ((events & mask) && !inode->func()) \
|
if ((events & mask) && !inode->func()) \
|
||||||
events &= ~mask;
|
events &= ~mask;
|
||||||
|
@ -79,6 +89,8 @@ namespace Kernel
|
||||||
CHECK_EVENT_BIT(EPOLLHUP, has_hungup);
|
CHECK_EVENT_BIT(EPOLLHUP, has_hungup);
|
||||||
#undef CHECK_EVENT_BIT
|
#undef CHECK_EVENT_BIT
|
||||||
|
|
||||||
|
inode->m_mutex.unlock();
|
||||||
|
|
||||||
if (events == 0)
|
if (events == 0)
|
||||||
{
|
{
|
||||||
m_ready_events.remove(it);
|
m_ready_events.remove(it);
|
||||||
|
@ -107,6 +119,8 @@ 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;
|
||||||
|
if (failed_lock)
|
||||||
|
continue;
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue