Serenity Operating System
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}