Serenity Operating System
at master 78 lines 2.2 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/Types.h> 10#include <Kernel/KBuffer.h> 11#include <Kernel/Locking/Mutex.h> 12#include <Kernel/Thread.h> 13#include <Kernel/UserOrKernelBuffer.h> 14 15namespace Kernel { 16 17class DoubleBuffer { 18public: 19 static ErrorOr<NonnullOwnPtr<DoubleBuffer>> try_create(StringView name, size_t capacity = 65536); 20 ErrorOr<size_t> write(UserOrKernelBuffer const&, size_t); 21 ErrorOr<size_t> write(u8 const* data, size_t size) 22 { 23 return write(UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>(data)), size); 24 } 25 ErrorOr<size_t> read(UserOrKernelBuffer&, size_t); 26 ErrorOr<size_t> read(u8* data, size_t size) 27 { 28 auto buffer = UserOrKernelBuffer::for_kernel_buffer(data); 29 return read(buffer, size); 30 } 31 ErrorOr<size_t> peek(UserOrKernelBuffer&, size_t); 32 ErrorOr<size_t> peek(u8* data, size_t size) 33 { 34 auto buffer = UserOrKernelBuffer::for_kernel_buffer(data); 35 return peek(buffer, size); 36 } 37 38 bool is_empty() const { return m_empty; } 39 40 size_t space_for_writing() const { return m_space_for_writing; } 41 size_t immediately_readable() const 42 { 43 return (m_read_buffer->size - m_read_buffer_index) + m_write_buffer->size; 44 } 45 46 void set_unblock_callback(Function<void()> callback) 47 { 48 VERIFY(!m_unblock_callback); 49 m_unblock_callback = move(callback); 50 } 51 52private: 53 explicit DoubleBuffer(size_t capacity, NonnullOwnPtr<KBuffer> storage); 54 void flip(); 55 void compute_lockfree_metadata(); 56 57 ErrorOr<size_t> read_impl(UserOrKernelBuffer&, size_t, MutexLocker&, bool advance_buffer_index); 58 59 struct InnerBuffer { 60 u8* data { nullptr }; 61 size_t size { 0 }; 62 }; 63 64 InnerBuffer* m_write_buffer { nullptr }; 65 InnerBuffer* m_read_buffer { nullptr }; 66 InnerBuffer m_buffer1; 67 InnerBuffer m_buffer2; 68 69 NonnullOwnPtr<KBuffer> m_storage; 70 Function<void()> m_unblock_callback; 71 size_t m_capacity { 0 }; 72 size_t m_read_buffer_index { 0 }; 73 size_t m_space_for_writing { 0 }; 74 bool m_empty { true }; 75 mutable Mutex m_lock { "DoubleBuffer"sv }; 76}; 77 78}