Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
async_stream.hpp
Go to the documentation of this file.
1#pragma once
2
3// AsyncStream — non-blocking wrapper around a synchronous Stream.
4//
5// AsyncStream owns a worker thread that pumps I/O on a Stream while the
6// caller continues on its own thread. Read data and completion callbacks
7// are delivered either on the worker thread (default) or dispatched into a
8// Pulp EventLoop when one is supplied.
9//
10// The wrapper adds three things the raw Stream does not:
11// - asynchronous callbacks for read data, errors, and close;
12// - a bounded write queue with explicit backpressure (`write` returns
13// false when the pending queue exceeds a high-water mark);
14// - cancellation — destruction, `cancel()`, or `close()` stops all
15// in-flight work and fires pending completion callbacks with a
16// Cancelled error.
17//
18// This is layer 2 of the Stream hierarchy. Layer 1 (`Stream`) provides a
19// synchronous interface; layer 3 adds network/HTTP-specific streams that
20// are already `Stream` subclasses and therefore automatically work with
21// `AsyncStream` without further adapter code.
22
25
26#include <atomic>
27#include <condition_variable>
28#include <cstddef>
29#include <cstdint>
30#include <functional>
31#include <memory>
32#include <mutex>
33#include <thread>
34#include <vector>
35
36namespace pulp::runtime {
37
42using AsyncExecutor = std::function<void(std::function<void()>)>;
43
48using AsyncWriteCallback = std::function<void(std::size_t bytes, StreamError error)>;
49
52using AsyncDataCallback = std::function<void(const std::uint8_t* data, std::size_t size)>;
53
57using AsyncErrorCallback = std::function<void(StreamError error)>;
58
62using AsyncCloseCallback = std::function<void()>;
63
66 std::size_t read_chunk = 4096;
67
72 std::size_t write_high_water = 1 << 20; // 1 MiB
73
76 bool auto_read = true;
77
83};
84
86public:
88
89 explicit AsyncStream(std::unique_ptr<Stream> stream, Options options = {});
91
92 AsyncStream(const AsyncStream&) = delete;
94
102
104 void start();
105
108 void stop();
109
112 void cancel();
113
117 [[nodiscard]] bool write_async(const std::uint8_t* data, std::size_t size,
118 AsyncWriteCallback callback = {});
119
121 std::size_t pending_write_bytes() const;
122
127 return source_.token();
128 }
129
132 Stream* stream() { return stream_.get(); }
133
134private:
135 struct PendingWrite {
136 std::vector<std::uint8_t> data;
137 std::size_t written = 0;
138 AsyncWriteCallback callback;
139 };
140
141 void write_loop();
142 void read_loop();
143 void dispatch(std::function<void()> task);
144 void fire_close();
145 void drain_queue_as_closed();
146
147 std::unique_ptr<Stream> stream_;
148 Options options_;
149 CancelSource source_;
150
151 AsyncDataCallback on_data_;
152 AsyncErrorCallback on_error_;
153 AsyncCloseCallback on_close_;
154 AsyncCloseCallback on_drain_;
155
156 mutable std::mutex mutex_;
157 std::condition_variable cv_;
158 std::vector<PendingWrite> write_queue_;
159 std::size_t pending_bytes_ = 0;
160 bool running_ = false;
161 bool close_fired_ = false;
162 std::thread writer_thread_;
163 std::thread reader_thread_;
164};
165
166} // namespace pulp::runtime
AsyncStreamOptions Options
Definition async_stream.hpp:87
CancelToken cancellation_token() const
Cancellation token shared with this stream's worker.
Definition async_stream.hpp:126
Stream * stream()
Underlying Stream, for advanced callers.
Definition async_stream.hpp:132
void on_data(AsyncDataCallback cb)
Attach callbacks.
std::size_t pending_write_bytes() const
Bytes currently queued for writing.
void on_close(AsyncCloseCallback cb)
void start()
Start the worker thread. No-op if already running.
bool write_async(const std::uint8_t *data, std::size_t size, AsyncWriteCallback callback={})
Queue an async write.
void stop()
Stop the worker thread and wait for it to exit.
void cancel()
Request cancellation.
AsyncStream(const AsyncStream &)=delete
AsyncStream & operator=(const AsyncStream &)=delete
void on_error(AsyncErrorCallback cb)
AsyncStream(std::unique_ptr< Stream > stream, Options options={})
void on_drain(AsyncCloseCallback cb)
fires when pending writes hit 0
Definition cancel.hpp:77
Base class for all Pulp byte streams.
Definition stream.hpp:62
Definition generated_event_source.hpp:33
std::function< void(const std::uint8_t *data, std::size_t size)> AsyncDataCallback
Incoming-data callback.
Definition async_stream.hpp:52
StreamError
High-level error classification for Stream operations.
Definition stream.hpp:31
std::function< void(std::function< void()>)> AsyncExecutor
Executor hook: a function that schedules work on some thread.
Definition async_stream.hpp:42
std::function< void()> AsyncCloseCallback
Close callback.
Definition async_stream.hpp:62
std::function< void(std::size_t bytes, StreamError error)> AsyncWriteCallback
Completion callback for write_async.
Definition async_stream.hpp:48
std::function< void(StreamError error)> AsyncErrorCallback
Error callback.
Definition async_stream.hpp:57
Definition async_stream.hpp:64
std::size_t read_chunk
Read chunk size (bytes) used by the background worker.
Definition async_stream.hpp:66
AsyncExecutor executor
Optional executor used to dispatch completion/data/error callbacks onto the caller's thread.
Definition async_stream.hpp:82
bool auto_read
When true, the worker reads from the stream eagerly and fires on_data callbacks.
Definition async_stream.hpp:76
std::size_t write_high_water
High-water mark for pending write bytes.
Definition async_stream.hpp:72