diff --git a/Userland/Libraries/LibCore/AnonymousBuffer.cpp b/Userland/Libraries/LibCore/AnonymousBuffer.cpp new file mode 100644 index 0000000000..d3087363b2 --- /dev/null +++ b/Userland/Libraries/LibCore/AnonymousBuffer.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2021, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__serenity__) +# include +# include +#endif + +namespace Core { + +AnonymousBuffer AnonymousBuffer::create_with_size(size_t size) +{ + int fd = -1; +#if defined(__serenity__) + fd = anon_create(round_up_to_power_of_two(size, PAGE_SIZE), O_CLOEXEC); + if (fd < 0) { + perror("anon_create"); + return {}; + } +#elif defined(__linux__) + fd = memfd_create("", MFD_CLOEXEC); + if (fd < 0) { + perror("memfd_create"); + return {}; + } + if (ftruncate(fd, size) < 0) { + perror("ftruncate"); + return {}; + } +#endif + if (fd < 0) + return {}; + return create_from_anon_fd(fd, size); +} + +RefPtr AnonymousBufferImpl::create(int fd, size_t size) +{ + auto* data = mmap(nullptr, round_up_to_power_of_two(size, PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + perror("mmap"); + return {}; + } + return adopt(*new AnonymousBufferImpl(fd, size, data)); +} + +AnonymousBufferImpl::~AnonymousBufferImpl() +{ + if (m_fd != -1) { + auto rc = close(m_fd); + ASSERT(rc == 0); + } + auto rc = munmap(m_data, round_up_to_power_of_two(m_size, PAGE_SIZE)); + ASSERT(rc == 0); +} + +AnonymousBuffer AnonymousBuffer::create_from_anon_fd(int fd, size_t size) +{ + auto impl = AnonymousBufferImpl::create(fd, size); + if (!impl) + return {}; + return AnonymousBuffer(impl.release_nonnull()); +} + +AnonymousBuffer::AnonymousBuffer(NonnullRefPtr impl) + : m_impl(move(impl)) +{ +} + +AnonymousBufferImpl::AnonymousBufferImpl(int fd, size_t size, void* data) + : m_fd(fd) + , m_size(size) + , m_data(data) +{ +} + +AnonymousBuffer::~AnonymousBuffer() +{ +} + +} diff --git a/Userland/Libraries/LibCore/AnonymousBuffer.h b/Userland/Libraries/LibCore/AnonymousBuffer.h new file mode 100644 index 0000000000..d65f892175 --- /dev/null +++ b/Userland/Libraries/LibCore/AnonymousBuffer.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace Core { + +class AnonymousBufferImpl final : public RefCounted { +public: + static RefPtr create(int fd, size_t); + ~AnonymousBufferImpl(); + + int fd() const { return m_fd; } + size_t size() const { return m_size; } + void* data() { return m_data; } + const void* data() const { return m_data; } + +private: + AnonymousBufferImpl(int fd, size_t, void*); + + int m_fd { -1 }; + size_t m_size { 0 }; + void* m_data { nullptr }; +}; + +class AnonymousBuffer { +public: + static AnonymousBuffer create_with_size(size_t); + static AnonymousBuffer create_from_anon_fd(int fd, size_t); + + AnonymousBuffer() { } + ~AnonymousBuffer(); + + bool is_valid() const { return m_impl; } + + int fd() const { return m_impl ? m_impl->fd() : -1; } + size_t size() const { return m_impl ? m_impl->size() : 0; } + + template + T* data() + { + static_assert(IsVoid::value || is_trivial()); + if (!m_impl) + return nullptr; + return (T*)m_impl->data(); + } + + template + const T* data() const + { + static_assert(IsVoid::value || is_trivial()); + if (!m_impl) + return nullptr; + return (const T*)m_impl->data(); + } + +private: + explicit AnonymousBuffer(NonnullRefPtr); + + RefPtr m_impl; +}; + +} + +namespace IPC { + +bool encode(Encoder&, const Core::AnonymousBuffer&); +bool decode(Decoder&, Core::AnonymousBuffer&); + +} diff --git a/Userland/Libraries/LibCore/CMakeLists.txt b/Userland/Libraries/LibCore/CMakeLists.txt index de16c64990..ee6c046bb9 100644 --- a/Userland/Libraries/LibCore/CMakeLists.txt +++ b/Userland/Libraries/LibCore/CMakeLists.txt @@ -1,5 +1,6 @@ set(SOURCES Account.cpp + AnonymousBuffer.cpp ArgsParser.cpp ConfigFile.cpp Command.cpp diff --git a/Userland/Libraries/LibCore/Forward.h b/Userland/Libraries/LibCore/Forward.h index 09497cb0bf..b9e36a9d49 100644 --- a/Userland/Libraries/LibCore/Forward.h +++ b/Userland/Libraries/LibCore/Forward.h @@ -28,6 +28,7 @@ namespace Core { +class AnonymousBuffer; class ArgsParser; class ChildEvent; class ConfigFile; diff --git a/Userland/Libraries/LibIPC/Decoder.cpp b/Userland/Libraries/LibIPC/Decoder.cpp index 96871f0b5b..5176d6ab12 100644 --- a/Userland/Libraries/LibIPC/Decoder.cpp +++ b/Userland/Libraries/LibIPC/Decoder.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -183,4 +184,24 @@ bool Decoder::decode([[maybe_unused]] File& file) #endif } +bool decode(Decoder& decoder, Core::AnonymousBuffer& buffer) +{ + bool valid = false; + if (!decoder.decode(valid)) + return false; + if (!valid) { + buffer = {}; + return true; + } + u32 size; + if (!decoder.decode(size)) + return false; + IPC::File anon_file; + if (!decoder.decode(anon_file)) + return false; + + buffer = Core::AnonymousBuffer::create_from_anon_fd(anon_file.take_fd(), size); + return buffer.is_valid(); +} + } diff --git a/Userland/Libraries/LibIPC/Encoder.cpp b/Userland/Libraries/LibIPC/Encoder.cpp index 240c3d927f..42aa60a675 100644 --- a/Userland/Libraries/LibIPC/Encoder.cpp +++ b/Userland/Libraries/LibIPC/Encoder.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -170,4 +171,13 @@ Encoder& Encoder::operator<<(const File& file) return *this; } +bool encode(Encoder& encoder, const Core::AnonymousBuffer& buffer) +{ + encoder << buffer.is_valid(); + if (buffer.is_valid()) { + encoder << (u32)buffer.size(); + encoder << IPC::File(buffer.fd()); + } + return true; +} }