Pigweed
 
Loading...
Searching...
No Matches
forwarding_channel.h
1// Copyright 2024 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <cstdint>
17#include <mutex>
18#include <optional>
19
20#include "pw_async2/dispatcher.h"
21#include "pw_async2/poll.h"
22#include "pw_channel/channel.h"
23#include "pw_multibuf/allocator.h"
24#include "pw_multibuf/allocator_async.h"
25#include "pw_sync/lock_annotations.h"
26#include "pw_sync/mutex.h"
27
28namespace pw::channel {
29namespace internal {
30
31// Internal Channel implementation for use with ForwardingChannelPair. It is
32// specialized for kDatagram and kByte.
33template <DataType kType>
35
36} // namespace internal
37
40
46template <DataType kType>
48 public:
49 explicit constexpr ForwardingChannelPair(
50 multibuf::MultiBufAllocator& first_write_alloc,
51 multibuf::MultiBufAllocator& second_write_alloc);
52
54 ForwardingChannelPair& operator=(const ForwardingChannelPair&) = delete;
55
57 ForwardingChannelPair& operator=(ForwardingChannelPair&&) = delete;
58
61 return first_.channel();
62 }
63
66 return first_;
67 }
68
71 return second_.channel();
72 }
73
76 return second_;
77 }
78
79 private:
80 template <DataType>
81 friend class internal::ForwardingChannel;
82
83 sync::Mutex mutex_;
84 // These channels refer to each other, so their lifetimes must match.
87};
88
92
95
97
98namespace internal {
99
100template <>
101class ForwardingChannel<DataType::kDatagram>
102 : public Implement<ReliableDatagramReaderWriter> {
103 public:
104 ForwardingChannel(const ForwardingChannel&) = delete;
105 ForwardingChannel& operator=(const ForwardingChannel&) = delete;
106
108 ForwardingChannel& operator=(ForwardingChannel&&) = delete;
109
110 private:
111 friend class ForwardingChannelPair<DataType::kDatagram>;
112
113 constexpr ForwardingChannel(ForwardingChannelPair<DataType::kDatagram>& pair,
114 ForwardingChannel* sibling,
115 multibuf::MultiBufAllocator& write_alloc)
116 : pair_(pair), sibling_(*sibling), write_alloc_future_(write_alloc) {}
117
119 async2::Context& cx) override;
120
121 async2::Poll<Status> DoPendReadyToWrite(async2::Context& cx) override;
122
123 async2::Poll<std::optional<multibuf::MultiBuf>> DoPendAllocateWriteBuffer(
124 async2::Context& cx, size_t min_bytes) override {
125 write_alloc_future_.SetDesiredSize(min_bytes);
126 return write_alloc_future_.Pend(cx);
127 }
128
129 Status DoStageWrite(multibuf::MultiBuf&& data) override;
130
131 async2::Poll<Status> DoPendWrite(async2::Context&) override {
132 return OkStatus();
133 }
134
135 async2::Poll<Status> DoPendClose(async2::Context&) override;
136
137 // The two channels share one mutex. Lock safty analysis doesn't understand
138 // that, so has to be disabled for some functions.
140 ForwardingChannel& sibling_;
141
142 // Could use a queue here.
143 std::optional<multibuf::MultiBuf> read_queue_ PW_GUARDED_BY(pair_.mutex_);
144 async2::Waker waker_ PW_GUARDED_BY(pair_.mutex_);
145 multibuf::MultiBufAllocationFuture write_alloc_future_;
146};
147
148template <>
149class ForwardingChannel<DataType::kByte>
150 : public Implement<ReliableByteReaderWriter> {
151 public:
152 ForwardingChannel(const ForwardingChannel&) = delete;
153 ForwardingChannel& operator=(const ForwardingChannel&) = delete;
154
156 ForwardingChannel& operator=(ForwardingChannel&&) = delete;
157
158 private:
159 friend class ForwardingChannelPair<DataType::kByte>;
160
161 constexpr ForwardingChannel(ForwardingChannelPair<DataType::kByte>& pair,
162 ForwardingChannel* sibling,
163 multibuf::MultiBufAllocator& write_alloc)
164 : pair_(pair), sibling_(*sibling), write_alloc_future_(write_alloc) {}
165
167 async2::Context& cx) override;
168
169 async2::Poll<Status> DoPendReadyToWrite(async2::Context&) override {
170 return async2::Ready(OkStatus());
171 }
172
173 async2::Poll<std::optional<multibuf::MultiBuf>> DoPendAllocateWriteBuffer(
174 async2::Context& cx, size_t min_bytes) override {
175 write_alloc_future_.SetDesiredSize(min_bytes);
176 return write_alloc_future_.Pend(cx);
177 }
178
179 Status DoStageWrite(multibuf::MultiBuf&& data) override;
180
181 async2::Poll<Status> DoPendWrite(async2::Context&) override {
182 return OkStatus();
183 }
184
185 async2::Poll<Status> DoPendClose(async2::Context&) override;
186
188 ForwardingChannel& sibling_;
189
190 multibuf::MultiBuf read_queue_ PW_GUARDED_BY(pair_.mutex_);
191 async2::Waker read_waker_ PW_GUARDED_BY(pair_.mutex_);
192 multibuf::MultiBufAllocationFuture write_alloc_future_;
193};
194
195} // namespace internal
196
197// Define the constructor out-of-line, after ForwardingChannel is defined.
198template <DataType kType>
200 multibuf::MultiBufAllocator& first_write_allocator,
201 multibuf::MultiBufAllocator& second_write_allocator)
202 : first_(*this, &second_, first_write_allocator),
203 second_(*this, &first_, second_write_allocator) {}
204
205} // namespace pw::channel
Definition: status.h:85
Definition: dispatcher_base.h:52
Definition: poll.h:54
Definition: dispatcher_base.h:318
Definition: channel.h:56
Definition: forwarding_channel.h:47
Channel< kType, kReliable, kReadable, kWritable > & second()
Returns the second channel in the pair.
Definition: forwarding_channel.h:70
Channel< kType, kReliable, kReadable, kWritable > & first()
Returns the first channel in the pair.
Definition: forwarding_channel.h:60
const Channel< kType, kReliable, kReadable, kWritable > & second() const
Returns a const reference to the second channel in the pair.
Definition: forwarding_channel.h:75
const Channel< kType, kReliable, kReadable, kWritable > & first() const
Returns a const reference to the first channel in the pair.
Definition: forwarding_channel.h:65
Definition: channel.h:583
Definition: forwarding_channel.h:34
Definition: allocator_async.h:90
Definition: allocator.h:54
Definition: multibuf.h:245
Definition: mutex.h:42
constexpr Status OkStatus()
Definition: status.h:234