Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
Channel.h
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * Jonas Rembser, CERN 2026
5 *
6 * Copyright (c) 2026, CERN
7 *
8 * Redistribution and use in source and binary forms,
9 * with or without modification, are permitted according to the terms
10 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
11 */
12#ifndef ROOT_ROOFIT_MultiProcess_Channel
13#define ROOT_ROOFIT_MultiProcess_Channel
14
16
17#include <cstdint>
18#include <cstring>
19#include <stdexcept>
20#include <string>
21#include <type_traits>
22#include <vector>
23
24namespace RooFit {
25namespace MultiProcess {
26
27/// Thrown when a blocking wait on a Channel is interrupted, e.g. by a signal.
28/// The errno-style number is available through num(), mirroring the interface
29/// of the zmq error types that were used here before, so the error handling
30/// logic in util.cxx could stay the same.
31class ppoll_error_t : public std::runtime_error {
32public:
33 explicit ppoll_error_t(int errnum, const std::string &what) : std::runtime_error(what), errnum_(errnum) {}
34 int num() const { return errnum_; }
35
36private:
38};
39
40/// \class Channel
41/// \brief One endpoint of a full-duplex interprocess message pipe
42///
43/// A Channel wraps one end of an AF_UNIX socketpair() created before forking
44/// the child processes, and provides framed, whole-message send and receive
45/// operations on top of the byte stream. Each frame is preceded by an 8-byte
46/// header containing the payload size and a "more" bit that marks all but the
47/// last frame of a multipart message.
48///
49/// Sends never block: bytes that the kernel socket buffer does not accept
50/// immediately are stored in a per-channel pending-output buffer, which is
51/// flushed opportunistically whenever any Channel in the process waits for
52/// input (see wait()). This mimics the previous ZeroMQ setup with an
53/// unlimited high-water mark and avoids send-send deadlocks between
54/// processes.
55class Channel {
56public:
57 Channel() = default;
58 /// Takes ownership of fd (one end of a socketpair) and makes it non-blocking.
59 explicit Channel(int fd);
60 ~Channel();
61
62 Channel(const Channel &) = delete;
63 Channel &operator=(const Channel &) = delete;
64 Channel(Channel &&other) noexcept;
65 Channel &operator=(Channel &&other) noexcept;
66
67 bool valid() const { return fd_ >= 0; }
68 int fd() const { return fd_; }
69
70 /// Queue one frame for sending and write out as much as the socket accepts.
71 void send_frame(const void *data, std::size_t size, bool more);
72
73 /// Non-blocking receive attempt. Returns true and fills msg/more when a
74 /// complete frame was received; returns false if more bytes are needed.
75 bool try_recv_frame(Message &msg, bool *more);
76
77 /// Blocking receive of one complete frame, interruptible by SIGTERM
78 /// (throws ppoll_error_t, like the poll functions).
79 Message recv_frame(bool *more = nullptr);
80
81 bool has_pending_output() const { return out_pos_ < out_buf_.size(); }
82 /// Write out pending output; returns true when all of it has been written.
83 bool try_flush();
84
85 /// Wait until at least one of read_channels has input available, flushing
86 /// the pending output of all live Channels in this process meanwhile.
87 /// Returns the indices into read_channels that are readable. A negative
88 /// timeout means wait forever; otherwise the result may be empty after
89 /// timeout_ms milliseconds. Throws ppoll_error_t with num() == EINTR when
90 /// interrupted by a signal (including the SIGTERM self-pipe wake-up).
91 static std::vector<std::size_t> wait(const std::vector<const Channel *> &read_channels, int timeout_ms);
92
93private:
94 void close_fd();
95 /// Handle end-of-stream / closed-connection conditions; never returns.
96 [[noreturn]] static void throw_connection_closed();
97
98 int fd_ = -1;
99
100 // outgoing bytes not yet accepted by the kernel socket buffer
101 std::vector<char> out_buf_;
102 std::size_t out_pos_ = 0;
103
104 // incoming frame in progress
105 std::uint64_t in_header_ = 0;
106 std::size_t in_header_bytes_ = 0;
107 bool in_have_header_ = false;
109 std::size_t in_msg_bytes_ = 0;
110};
111
112// Helper functions to send/receive single typed items over a Channel. These
113// implement the same wire conventions as the old ZeroMQSvc encode/decode:
114// trivially copyable types are sent as their raw bytes, strings as their
115// character contents, and Message objects pass through as-is.
116
118 !std::is_pointer<typename std::decay<T>::type>::value,
119 bool>::type = true>
120void send_item(Channel &channel, const T &item, bool more)
121{
122 channel.send_frame(&item, sizeof(T), more);
123}
124
125inline void send_item(Channel &channel, const std::string &item, bool more)
126{
127 channel.send_frame(item.data(), item.size(), more);
128}
129
130inline void send_item(Channel &channel, const char *item, bool more)
131{
132 channel.send_frame(item, std::strlen(item), more);
133}
134
135inline void send_item(Channel &channel, const Message &item, bool more)
136{
137 channel.send_frame(item.data(), item.size(), more);
138}
139
140template <typename value_t>
141value_t receive_item(Channel &channel, bool *more = nullptr)
142{
143 Message msg = channel.recv_frame(more);
144 if constexpr (std::is_same<value_t, Message>::value) {
145 return msg;
146 } else if constexpr (std::is_same<value_t, std::string>::value) {
147 return std::string(msg.data<char>(), msg.size());
148 } else {
149 static_assert(std::is_trivially_copyable<value_t>::value,
150 "only trivially copyable types, std::string and Message can be received");
151 if (msg.size() != sizeof(value_t)) {
152 throw std::runtime_error("MultiProcess::receive_item: message size does not match receive type");
153 }
154 value_t value;
155 std::memcpy(&value, msg.data(), sizeof(value_t));
156 return value;
157 }
158}
159
160} // namespace MultiProcess
161} // namespace RooFit
162
163#endif // ROOT_ROOFIT_MultiProcess_Channel
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
One endpoint of a full-duplex interprocess message pipe.
Definition Channel.h:55
bool has_pending_output() const
Definition Channel.h:81
Channel(const Channel &)=delete
void send_frame(const void *data, std::size_t size, bool more)
Queue one frame for sending and write out as much as the socket accepts.
Definition Channel.cxx:158
static void throw_connection_closed()
Handle end-of-stream / closed-connection conditions; never returns.
Definition Channel.cxx:139
bool try_recv_frame(Message &msg, bool *more)
Non-blocking receive attempt.
Definition Channel.cxx:198
static std::vector< std::size_t > wait(const std::vector< const Channel * > &read_channels, int timeout_ms)
Wait until at least one of read_channels has input available, flushing the pending output of all live...
Definition Channel.cxx:264
Channel & operator=(const Channel &)=delete
bool try_flush()
Write out pending output; returns true when all of it has been written.
Definition Channel.cxx:177
Message recv_frame(bool *more=nullptr)
Blocking receive of one complete frame, interruptible by SIGTERM (throws ppoll_error_t,...
Definition Channel.cxx:255
std::vector< char > out_buf_
Definition Channel.h:101
A contiguous byte buffer used as the unit of interprocess communication.
Definition Message.h:30
Thrown when a blocking wait on a Channel is interrupted, e.g.
Definition Channel.h:31
ppoll_error_t(int errnum, const std::string &what)
Definition Channel.h:33
value_t receive_item(Channel &channel, bool *more=nullptr)
Definition Channel.h:141
void send_item(Channel &channel, const T &item, bool more)
Definition Channel.h:120
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Definition CodegenImpl.h:73
static const char * what
Definition stlLoader.cc:5