1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-01 03:08:13 +00:00

Kernel: Allow Lock to block from BlockCondition

This enables the Lock class to block a thread even while the thread is
working on a BlockCondition. A thread can still only be either blocked
by a Lock or a BlockCondition.

This also establishes a linked list of threads that are blocked by a
Lock and unblocking directly unlocks threads and wakes them directly.
This commit is contained in:
Tom 2021-07-10 10:23:16 -06:00 committed by Andreas Kling
parent d9fb93c5ce
commit 026ffa343d
8 changed files with 442 additions and 267 deletions

View file

@ -436,7 +436,7 @@ PageFaultResponse Region::handle_fault(const PageFault& fault, ScopedSpinLock<Re
remap_vmobject_page(translate_to_vmobject_page(page_index_in_region));
return PageFaultResponse::Continue;
}
return handle_zero_fault(page_index_in_region);
return handle_zero_fault(page_index_in_region, mm_lock);
#else
dbgln("BUG! Unexpected NP fault at {}", fault.vaddr());
return PageFaultResponse::ShouldCrash;
@ -448,7 +448,7 @@ PageFaultResponse Region::handle_fault(const PageFault& fault, ScopedSpinLock<Re
auto* phys_page = physical_page(page_index_in_region);
if (phys_page->is_shared_zero_page() || phys_page->is_lazy_committed_page()) {
dbgln_if(PAGE_FAULT_DEBUG, "NP(zero) fault in Region({})[{}] at {}", this, page_index_in_region, fault.vaddr());
return handle_zero_fault(page_index_in_region);
return handle_zero_fault(page_index_in_region, mm_lock);
}
return handle_cow_fault(page_index_in_region);
}
@ -456,12 +456,29 @@ PageFaultResponse Region::handle_fault(const PageFault& fault, ScopedSpinLock<Re
return PageFaultResponse::ShouldCrash;
}
PageFaultResponse Region::handle_zero_fault(size_t page_index_in_region)
PageFaultResponse Region::handle_zero_fault(size_t page_index_in_region, ScopedSpinLock<RecursiveSpinLock>& mm_lock)
{
VERIFY_INTERRUPTS_DISABLED();
VERIFY(vmobject().is_anonymous());
Locker locker(vmobject().m_paging_lock);
bool can_lock = Thread::current() && !g_scheduler_lock.own_lock();
if (can_lock) {
// TODO: This seems rather weird. If we don't have a current thread
// then we're in the Kernel in early initialization still. So we
// can't actually wait on the paging lock. And if we currently
// own the scheduler lock and we trigger zero faults, we also
// can't really wait. But do we actually need to wait here?
mm_lock.unlock();
VERIFY(!s_mm_lock.own_lock());
vmobject().m_paging_lock.lock();
mm_lock.lock();
}
ScopeGuard guard([&]() {
if (can_lock)
vmobject().m_paging_lock.unlock();
});
auto& page_slot = physical_page_slot(page_index_in_region);
auto page_index_in_vmobject = translate_to_vmobject_page(page_index_in_region);