aboutsummaryrefslogtreecommitdiff
path: root/src/zenutil/process/asyncpipereader.h
blob: ad2ff845567b1a5d8daa8c373a694a030f8ee0e5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include <zencore/process.h>
#include <zencore/zencore.h>

#include <functional>
#include <memory>
#include <string_view>

namespace asio {
class io_context;
}

namespace zen {

/// Create an overlapped pipe pair suitable for async I/O on Windows.
///
/// Unlike CreateStdoutPipe() (which creates anonymous non-overlapped pipes),
/// this creates a named pipe with FILE_FLAG_OVERLAPPED on the read end, so it
/// can be used with asio::windows::stream_handle for fully async reads.
/// The write end is inheritable and suitable for child process redirection.
///
/// On non-Windows platforms this simply delegates to CreateStdoutPipe().
bool CreateOverlappedStdoutPipe(StdoutPipeHandles& OutPipe);

/// Async pipe reader for capturing child process stdout/stderr.
///
/// Takes ownership of a pipe's read end and reads asynchronously:
///   Linux/macOS: non-blocking fd + asio::posix::stream_descriptor
///   Windows:     overlapped named pipe + asio::windows::stream_handle
///
/// On Windows the pipe must have been created with CreateOverlappedStdoutPipe()
/// for async I/O to work. Pipes from CreateStdoutPipe() will fail.
///
/// DataCallback is invoked for each chunk read (on the io_context).
/// EofCallback is invoked when the pipe closes (child exited or pipe broken).
class AsyncPipeReader
{
public:
	explicit AsyncPipeReader(asio::io_context& IoContext);
	~AsyncPipeReader();

	AsyncPipeReader(const AsyncPipeReader&) = delete;
	AsyncPipeReader& operator=(const AsyncPipeReader&) = delete;

	/// Take ownership of the pipe read-end and start async reading.
	/// The write end is closed immediately (caller should have already launched
	/// the child process). DataCallback receives raw chunks. EofCallback fires
	/// once when the pipe reaches EOF.
	void Start(StdoutPipeHandles&& Pipe, std::function<void(std::string_view Data)> DataCallback, std::function<void()> EofCallback);

	/// Stop reading and close the pipe. Callbacks will not fire after this returns.
	void Stop();

private:
	struct Impl;
	std::unique_ptr<Impl> m_Impl;
};

}  // namespace zen