diff options
author | Robin Burchell <robin+git@viroteck.net> | 2019-07-19 23:14:56 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-07-20 12:15:11 +0200 |
commit | 56217c743260d6db839ccb3ce8f99b14d7973627 (patch) | |
tree | d470028121227ccf40290703a5b05139d0007c20 | |
parent | 253e391bfc84b2b99443e664b10cc332c22eb97a (diff) | |
download | serenity-56217c743260d6db839ccb3ce8f99b14d7973627.zip |
SharedBuffer: Amend commit 2d4d465206d
I had the right cause of the SharedBuffer leak, but goofed the fix by
desynching the per-pid refcount and the global refcount.
Fix that, and add a generous sprinkle of asserts to make sure the two
stay in sync.
Fixes #341
(... for real this time)
-rw-r--r-- | Kernel/SharedBuffer.cpp | 29 | ||||
-rw-r--r-- | Kernel/SharedBuffer.h | 1 |
2 files changed, 29 insertions, 1 deletions
diff --git a/Kernel/SharedBuffer.cpp b/Kernel/SharedBuffer.cpp index a082555bae..7fe077b5c8 100644 --- a/Kernel/SharedBuffer.cpp +++ b/Kernel/SharedBuffer.cpp @@ -9,6 +9,23 @@ Lockable<HashMap<int, OwnPtr<SharedBuffer>>>& shared_buffers() return *map; } +void SharedBuffer::sanity_check(const char* what) +{ + LOCKER(shared_buffers().lock()); + + unsigned found_refs = 0; + for (const auto& ref : m_refs) + found_refs += ref.count; + + if (found_refs != m_total_refs) { + dbgprintf("%s sanity -- SharedBuffer{%p} id: %d has total refs %d but we found %d\n", what, this, m_shared_buffer_id, m_total_refs, found_refs); + for (const auto& ref : m_refs) { + dbgprintf(" ref from pid %d: refcnt %d\n", ref.pid, ref.count); + } + ASSERT_NOT_REACHED(); + } +} + bool SharedBuffer::is_shared_with(pid_t peer_pid) { LOCKER(shared_buffers().lock()); @@ -33,6 +50,7 @@ void* SharedBuffer::ref_for_process_and_get_address(Process& process) ref.region = process.allocate_region_with_vmo(VirtualAddress(), size(), m_vmo, 0, "SharedBuffer", PROT_READ | (m_writable ? PROT_WRITE : 0)); ref.region->set_shared(true); } + sanity_check("ref_for_process_and_get_address"); return ref.region->vaddr().as_ptr(); } } @@ -45,11 +63,13 @@ void SharedBuffer::share_with(pid_t peer_pid) for (auto& ref : m_refs) { if (ref.pid == peer_pid) { // don't increment the reference count yet; let them get_shared_buffer it first. + sanity_check("share_with (old ref)"); return; } } m_refs.append(Reference(peer_pid)); + sanity_check("share_with (new ref)"); } void SharedBuffer::deref_for_process(Process& process) @@ -58,7 +78,9 @@ void SharedBuffer::deref_for_process(Process& process) for (int i = 0; i < m_refs.size(); ++i) { auto& ref = m_refs[i]; if (ref.pid == process.pid()) { - if (--ref.count == 0) { + ref.count--; + m_total_refs--; + if (ref.count == 0) { #ifdef SHARED_BUFFER_DEBUG dbgprintf("Releasing shared buffer reference on %d of size %d by PID %d\n", m_shared_buffer_id, size(), process.pid()); #endif @@ -67,11 +89,14 @@ void SharedBuffer::deref_for_process(Process& process) #ifdef SHARED_BUFFER_DEBUG dbgprintf("Released shared buffer reference on %d of size %d by PID %d\n", m_shared_buffer_id, size(), process.pid()); #endif + sanity_check("deref_for_process"); destroy_if_unused(); return; } } } + + ASSERT_NOT_REACHED(); } void SharedBuffer::disown(pid_t pid) @@ -83,6 +108,7 @@ void SharedBuffer::disown(pid_t pid) #ifdef SHARED_BUFFER_DEBUG dbgprintf("Disowning shared buffer %d of size %d by PID %d\n", m_shared_buffer_id, size(), pid); #endif + m_total_refs -= ref.count; m_refs.remove(i); #ifdef SHARED_BUFFER_DEBUG dbgprintf("Disowned shared buffer %d of size %d by PID %d\n", m_shared_buffer_id, size(), pid); @@ -96,6 +122,7 @@ void SharedBuffer::disown(pid_t pid) void SharedBuffer::destroy_if_unused() { LOCKER(shared_buffers().lock()); + sanity_check("destroy_if_unused"); if (m_total_refs == 0) { #ifdef SHARED_BUFFER_DEBUG kprintf("Destroying unused SharedBuffer{%p} id: %d\n", this, m_shared_buffer_id); diff --git a/Kernel/SharedBuffer.h b/Kernel/SharedBuffer.h index c2d4d05ec5..6b408bb3f8 100644 --- a/Kernel/SharedBuffer.h +++ b/Kernel/SharedBuffer.h @@ -32,6 +32,7 @@ public: #endif } + void sanity_check(const char* what); bool is_shared_with(pid_t peer_pid); void* ref_for_process_and_get_address(Process& process); void share_with(pid_t peer_pid); |