diff options
author | Robin Burchell <robin+git@viroteck.net> | 2019-07-15 20:38:41 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-07-16 10:03:14 +0200 |
commit | df3e295ba6ee69f0b178c581f1d91f8c322c0c4d (patch) | |
tree | 12dea09a0b472b29e9e81bd44f16353e2d751e26 | |
parent | 6e90f00925e3f30bebd252bedd8279bb12760e18 (diff) | |
download | serenity-df3e295ba6ee69f0b178c581f1d91f8c322c0c4d.zip |
Kernel: SharedBuffer sharing cleanup
Rather than limiting it to two shared processes, store a Vector of
references, so we can add more if we want. Makes the code a little
more generic.
No actual change to the syscall interface yet, so nothing takes
advantage of this yet.
-rw-r--r-- | Kernel/Process.cpp | 182 |
1 files changed, 105 insertions, 77 deletions
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 9d7031da44..4c18348958 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -31,7 +31,7 @@ //#define DEBUG_IO //#define TASK_DEBUG //#define FORK_DEBUG -#define SIGNAL_DEBUG +//#define SIGNAL_DEBUG //#define SHARED_BUFFER_DEBUG static pid_t next_pid; @@ -2367,101 +2367,127 @@ int Process::sys$setsockopt(const Syscall::SC_setsockopt_params* params) } struct SharedBuffer { - SharedBuffer(pid_t pid1, pid_t pid2, int size) - : m_pid1(pid1) - , m_pid2(pid2) +private: + struct Reference { + Reference(pid_t pid) + : pid(pid) + { + } + + pid_t pid; + unsigned count { 1 }; + Region* region { nullptr }; + }; +public: + SharedBuffer(int id, int size) + : m_shared_buffer_id(id) , m_vmo(VMObject::create_anonymous(size)) { - ASSERT(pid1 != pid2); +#ifdef SHARED_BUFFER_DEBUG + dbgprintf("Created shared buffer %d of size %d\n", m_shared_buffer_id, size); +#endif + } + + ~SharedBuffer() + { +#ifdef SHARED_BUFFER_DEBUG + dbgprintf("Destroyed shared buffer %d of size %d\n", m_shared_buffer_id, size()); +#endif } - void* retain(Process& process) + bool is_shared_with(pid_t peer_pid) { - if (m_pid1 == process.pid()) { - ++m_pid1_retain_count; - if (!m_pid1_region) { - m_pid1_region = process.allocate_region_with_vmo(VirtualAddress(), size(), m_vmo, 0, "SharedBuffer", PROT_READ | (m_pid1_writable ? PROT_WRITE : 0)); - m_pid1_region->set_shared(true); + LOCKER(m_refs.lock()); + for (auto& ref : m_refs.resource()) { + if (ref.pid == peer_pid) { + return true; } - return m_pid1_region->vaddr().as_ptr(); - } else if (m_pid2 == process.pid()) { - ++m_pid2_retain_count; - if (!m_pid2_region) { - m_pid2_region = process.allocate_region_with_vmo(VirtualAddress(), size(), m_vmo, 0, "SharedBuffer", PROT_READ | (m_pid2_writable ? PROT_WRITE : 0)); - m_pid2_region->set_shared(true); + } + + return false; + } + + void* get_address(Process& process) + { + LOCKER(m_refs.lock()); + ASSERT(is_shared_with(process.pid())); + for (auto& ref : m_refs.resource()) { + if (ref.pid == process.pid()) { + if (ref.region == nullptr) { + 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); + } + return ref.region->vaddr().as_ptr(); } - return m_pid2_region->vaddr().as_ptr(); } - return nullptr; + ASSERT_NOT_REACHED(); } - void release(Process& process) + void share_with(pid_t peer_pid) { - if (m_pid1 == process.pid()) { - ASSERT(m_pid1_retain_count); - --m_pid1_retain_count; - if (!m_pid1_retain_count) { - if (m_pid1_region) - process.deallocate_region(*m_pid1_region); - m_pid1_region = nullptr; + LOCKER(m_refs.lock()); + for (auto& ref : m_refs.resource()) { + if (ref.pid == peer_pid) { + ref.count++; + return; } - destroy_if_unused(); - } else if (m_pid2 == process.pid()) { - ASSERT(m_pid2_retain_count); - --m_pid2_retain_count; - if (!m_pid2_retain_count) { - if (m_pid2_region) - process.deallocate_region(*m_pid2_region); - m_pid2_region = nullptr; + } + + m_refs.resource().append(Reference(peer_pid)); + } + + void release(Process& process) + { + LOCKER(m_refs.lock()); +#ifdef SHARED_BUFFER_DEBUG + dbgprintf("Releasing shared buffer %d of size %d by PID %d\n", m_shared_buffer_id, size(), process.pid()); +#endif + for (int i = 0; i < m_refs.resource().size(); ++i) { + auto& ref = m_refs.resource()[i]; + if (ref.pid == process.pid()) { + if (--ref.count == 0) { + process.deallocate_region(*ref.region); + m_refs.resource().remove(i); + destroy_if_unused(); + return; + } } - destroy_if_unused(); } } void disown(pid_t pid) { - if (m_pid1 == pid) { - m_pid1 = 0; - m_pid1_retain_count = 0; - destroy_if_unused(); - } else if (m_pid2 == pid) { - m_pid2 = 0; - m_pid2_retain_count = 0; - destroy_if_unused(); + LOCKER(m_refs.lock()); +#ifdef SHARED_BUFFER_DEBUG + dbgprintf("Disowning shared buffer %d of size %d by PID %d\n", m_shared_buffer_id, size(), pid); +#endif + for (int i = 0; i < m_refs.resource().size(); ++i) { + auto& ref = m_refs.resource()[i]; + if (ref.pid == pid) { + m_refs.resource().remove(i); + destroy_if_unused(); + return; + } } } - pid_t pid1() const { return m_pid1; } - pid_t pid2() const { return m_pid2; } - unsigned pid1_ref_count() const { return m_pid1_retain_count; } - unsigned pid2_ref_count() const { return m_pid2_retain_count; } size_t size() const { return m_vmo->size(); } void destroy_if_unused(); void seal() { - m_pid1_writable = false; - m_pid2_writable = false; - if (m_pid1_region) { - m_pid1_region->set_writable(false); - MM.remap_region(*m_pid1_region->page_directory(), *m_pid1_region); - } - if (m_pid2_region) { - m_pid2_region->set_writable(false); - MM.remap_region(*m_pid2_region->page_directory(), *m_pid2_region); + LOCKER(m_refs.lock()); + m_writable = false; + for (auto& ref : m_refs.resource()) { + ref.region->set_writable(false); + MM.remap_region(*ref.region->page_directory(), *ref.region); } } int m_shared_buffer_id { -1 }; - pid_t m_pid1; - pid_t m_pid2; - unsigned m_pid1_retain_count { 1 }; - unsigned m_pid2_retain_count { 0 }; - Region* m_pid1_region { nullptr }; - Region* m_pid2_region { nullptr }; - bool m_pid1_writable { false }; - bool m_pid2_writable { false }; + bool m_writable { true }; NonnullRefPtr<VMObject> m_vmo; + Lockable<Vector<Reference, 2>> m_refs; }; static int s_next_shared_buffer_id; @@ -2475,10 +2501,11 @@ Lockable<HashMap<int, OwnPtr<SharedBuffer>>>& shared_buffers() void SharedBuffer::destroy_if_unused() { - if (!m_pid1_retain_count && !m_pid2_retain_count) { + LOCKER(m_refs.lock()); + if (m_refs.resource().size() == 0) { LOCKER(shared_buffers().lock()); #ifdef SHARED_BUFFER_DEBUG - kprintf("Destroying unused SharedBuffer{%p} id: %d (pid1: %d, pid2: %d)\n", this, m_shared_buffer_id, m_pid1, m_pid2); + kprintf("Destroying unused SharedBuffer{%p} id: %d\n", this, m_shared_buffer_id); #endif auto count_before = shared_buffers().resource().size(); shared_buffers().resource().remove(m_shared_buffer_id); @@ -2505,6 +2532,7 @@ int Process::sys$create_shared_buffer(pid_t peer_pid, int size, void** buffer) return -EINVAL; if (!validate_write_typed(buffer)) return -EFAULT; + { InterruptDisabler disabler; auto* peer = Process::from_pid(peer_pid); @@ -2513,16 +2541,16 @@ int Process::sys$create_shared_buffer(pid_t peer_pid, int size, void** buffer) } LOCKER(shared_buffers().lock()); int shared_buffer_id = ++s_next_shared_buffer_id; - auto shared_buffer = make<SharedBuffer>(m_pid, peer_pid, size); - shared_buffer->m_shared_buffer_id = shared_buffer_id; + auto shared_buffer = make<SharedBuffer>(shared_buffer_id, size); + shared_buffer->share_with(m_pid); + shared_buffer->share_with(peer_pid); + *buffer = shared_buffer->get_address(*this); ASSERT((int)shared_buffer->size() >= size); - shared_buffer->m_pid1_region = allocate_region_with_vmo(VirtualAddress(), shared_buffer->size(), shared_buffer->m_vmo, 0, "SharedBuffer", PROT_READ | PROT_WRITE); - shared_buffer->m_pid1_region->set_shared(true); - *buffer = shared_buffer->m_pid1_region->vaddr().as_ptr(); #ifdef SHARED_BUFFER_DEBUG - kprintf("%s(%u): Created shared buffer %d (%u bytes, vmo is %u) for sharing with %d\n", name().characters(), pid(), shared_buffer_id, size, shared_buffer->size(), peer_pid); + kprintf("%s(%u): Created shared buffer %d @ %p (%u bytes, vmo is %u)\n", name().characters(), pid(), shared_buffer_id, *buffer, size, shared_buffer->size()); #endif shared_buffers().resource().set(shared_buffer_id, move(shared_buffer)); + return shared_buffer_id; } @@ -2547,12 +2575,12 @@ void* Process::sys$get_shared_buffer(int shared_buffer_id) if (it == shared_buffers().resource().end()) return (void*)-EINVAL; auto& shared_buffer = *(*it).value; - if (shared_buffer.pid1() != m_pid && shared_buffer.pid2() != m_pid) + if (!shared_buffer.is_shared_with(m_pid)) return (void*)-EINVAL; #ifdef SHARED_BUFFER_DEBUG kprintf("%s(%u): Retaining shared buffer %d, buffer count: %u\n", name().characters(), pid(), shared_buffer_id, shared_buffers().resource().size()); #endif - return shared_buffer.retain(*this); + return shared_buffer.get_address(*this); } int Process::sys$seal_shared_buffer(int shared_buffer_id) @@ -2562,7 +2590,7 @@ int Process::sys$seal_shared_buffer(int shared_buffer_id) if (it == shared_buffers().resource().end()) return -EINVAL; auto& shared_buffer = *(*it).value; - if (shared_buffer.pid1() != m_pid && shared_buffer.pid2() != m_pid) + if (!shared_buffer.is_shared_with(m_pid)) return -EINVAL; #ifdef SHARED_BUFFER_DEBUG kprintf("%s(%u): Sealing shared buffer %d\n", name().characters(), pid(), shared_buffer_id); @@ -2578,7 +2606,7 @@ int Process::sys$get_shared_buffer_size(int shared_buffer_id) if (it == shared_buffers().resource().end()) return -EINVAL; auto& shared_buffer = *(*it).value; - if (shared_buffer.pid1() != m_pid && shared_buffer.pid2() != m_pid) + if (!shared_buffer.is_shared_with(m_pid)) return -EINVAL; #ifdef SHARED_BUFFER_DEBUG kprintf("%s(%u): Get shared buffer %d size: %u\n", name().characters(), pid(), shared_buffer_id, shared_buffers().resource().size()); |