Skip to content

Commit 9393aee

Browse files
committed
Merge bitcoin#32641: Update libmultiprocess subtree to fix clang-tidy errors
154af1e Squashed 'src/ipc/libmultiprocess/' changes from 35944ffd23fa..27c7e8e5a581 (Ryan Ofsky) Pull request description: Includes: - bitcoin-core/libmultiprocess#165 - bitcoin-core/libmultiprocess#173 - bitcoin-core/libmultiprocess#172 These changes are needed to fix CI errors in bitcoin#31802. The changes can be verified by running `test/lint/git-subtree-check.sh src/ipc/libmultiprocess` as described in [developer notes](https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md#subtrees) and [lint instructions](https://github.com/bitcoin/bitcoin/tree/master/test/lint#git-subtree-checksh) ACKs for top commit: Sjors: ACK 9f65654 TheCharlatan: ACK 9f65654 Tree-SHA512: 745789a6fba552aa066f9f69592b16a5277999dbf0413eaed7fe25cd440b78af57615edfce781592873659fda91463bef7c5dac202b80362bd86f6a90ab20d69
2 parents 5471e29 + 9f65654 commit 9393aee

File tree

8 files changed

+108
-82
lines changed

8 files changed

+108
-82
lines changed

src/ipc/libmultiprocess/include/mp/proxy-io.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ class EventLoop
172172
void addClient(std::unique_lock<std::mutex>& lock);
173173
bool removeClient(std::unique_lock<std::mutex>& lock);
174174
//! Check if loop should exit.
175-
bool done(std::unique_lock<std::mutex>& lock);
175+
bool done(std::unique_lock<std::mutex>& lock) const;
176176

177177
Logger log()
178178
{
@@ -249,7 +249,7 @@ struct Waiter
249249
{
250250
const std::unique_lock<std::mutex> lock(m_mutex);
251251
assert(!m_fn);
252-
m_fn = std::move(fn);
252+
m_fn = std::forward<Fn>(fn);
253253
m_cv.notify_all();
254254
}
255255

@@ -333,7 +333,7 @@ class Connection
333333
// to the EventLoop TaskSet to avoid "Promise callback destroyed itself"
334334
// error in cases where f deletes this Connection object.
335335
m_on_disconnect.add(m_network.onDisconnect().then(
336-
[f = std::move(f), this]() mutable { m_loop.m_task_set->add(kj::evalLater(kj::mv(f))); }));
336+
[f = std::forward<F>(f), this]() mutable { m_loop.m_task_set->add(kj::evalLater(kj::mv(f))); }));
337337
}
338338

339339
EventLoop& m_loop;
@@ -634,7 +634,10 @@ void ListenConnections(EventLoop& loop, int fd, InitImpl& init)
634634
});
635635
}
636636

637-
extern thread_local ThreadContext g_thread_context;
637+
extern thread_local ThreadContext g_thread_context; // NOLINT(bitcoin-nontrivial-threadlocal)
638+
// Silence nonstandard bitcoin tidy error "Variable with non-trivial destructor
639+
// cannot be thread_local" which should not be a problem on modern platforms, and
640+
// could lead to a small memory leak at worst on older ones.
638641

639642
} // namespace mp
640643

src/ipc/libmultiprocess/include/mp/proxy-types.h

Lines changed: 72 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,45 @@ struct StructField
3737
}
3838
Struct& m_struct;
3939

40-
// clang-format off
41-
template<typename A = Accessor> auto get() const -> decltype(A::get(this->m_struct)) { return A::get(this->m_struct); }
42-
template<typename A = Accessor> auto has() const -> std::enable_if_t<A::optional, bool> { return A::getHas(m_struct); }
43-
template<typename A = Accessor> auto has() const -> std::enable_if_t<!A::optional && A::boxed, bool> { return A::has(m_struct); }
44-
template<typename A = Accessor> auto has() const -> std::enable_if_t<!A::optional && !A::boxed, bool> { return true; }
45-
template<typename A = Accessor> auto want() const -> std::enable_if_t<A::requested, bool> { return A::getWant(m_struct); }
46-
template<typename A = Accessor> auto want() const -> std::enable_if_t<!A::requested, bool> { return true; }
47-
template<typename A = Accessor, typename... Args> decltype(auto) set(Args&&... args) const { return A::set(this->m_struct, std::forward<Args>(args)...); }
48-
template<typename A = Accessor, typename... Args> decltype(auto) init(Args&&... args) const { return A::init(this->m_struct, std::forward<Args>(args)...); }
49-
template<typename A = Accessor> auto setHas() const -> std::enable_if_t<A::optional> { return A::setHas(m_struct); }
50-
template<typename A = Accessor> auto setHas() const -> std::enable_if_t<!A::optional> { }
51-
template<typename A = Accessor> auto setWant() const -> std::enable_if_t<A::requested> { return A::setWant(m_struct); }
52-
template<typename A = Accessor> auto setWant() const -> std::enable_if_t<!A::requested> { }
53-
// clang-format on
40+
decltype(auto) get() const { return Accessor::get(this->m_struct); }
41+
42+
bool has() const {
43+
if constexpr (Accessor::optional) {
44+
return Accessor::getHas(m_struct);
45+
} else if constexpr (Accessor::boxed) {
46+
return Accessor::has(m_struct);
47+
} else {
48+
return true;
49+
}
50+
}
51+
52+
bool want() const {
53+
if constexpr (Accessor::requested) {
54+
return Accessor::getWant(m_struct);
55+
} else {
56+
return true;
57+
}
58+
}
59+
60+
template <typename... Args> decltype(auto) set(Args &&...args) const {
61+
return Accessor::set(this->m_struct, std::forward<Args>(args)...);
62+
}
63+
64+
template <typename... Args> decltype(auto) init(Args &&...args) const {
65+
return Accessor::init(this->m_struct, std::forward<Args>(args)...);
66+
}
67+
68+
void setHas() const {
69+
if constexpr (Accessor::optional) {
70+
Accessor::setHas(m_struct);
71+
}
72+
}
73+
74+
void setWant() const {
75+
if constexpr (Accessor::requested) {
76+
Accessor::setWant(m_struct);
77+
}
78+
}
5479
};
5580

5681

@@ -360,34 +385,28 @@ struct ClientException
360385
template <typename Accessor, typename... Types>
361386
struct ClientParam
362387
{
363-
ClientParam(Types&&... values) : m_values(values...) {}
388+
ClientParam(Types&&... values) : m_values{std::forward<Types>(values)...} {}
364389

365390
struct BuildParams : IterateFieldsHelper<BuildParams, sizeof...(Types)>
366391
{
367-
template <typename... Args>
368-
void handleField(Args&&... args)
369-
{
370-
callBuild<0>(std::forward<Args>(args)...);
371-
}
372-
373-
// TODO Possible optimization to speed up compile time:
374-
// https://stackoverflow.com/a/7858971 Using enable_if below to check
375-
// position when unpacking tuple might be slower than pattern matching
376-
// approach in the stack overflow solution
377-
template <size_t I, typename... Args>
378-
auto callBuild(Args&&... args) -> std::enable_if_t<(I < sizeof...(Types))>
379-
{
380-
callBuild<I + 1>(std::forward<Args>(args)..., std::get<I>(m_client_param->m_values));
381-
}
382-
383-
template <size_t I, typename Params, typename ParamList, typename... Values>
384-
auto callBuild(ClientInvokeContext& invoke_context, Params& params, ParamList, Values&&... values) ->
385-
std::enable_if_t<(I == sizeof...(Types))>
392+
template <typename Params, typename ParamList>
393+
void handleField(ClientInvokeContext& invoke_context, Params& params, ParamList)
386394
{
387-
MaybeBuildField(std::integral_constant<bool, Accessor::in>(), ParamList(), invoke_context,
388-
Make<StructField, Accessor>(params), std::forward<Values>(values)...);
389-
MaybeSetWant(
390-
ParamList(), Priority<1>(), std::forward<Values>(values)..., Make<StructField, Accessor>(params));
395+
auto const fun = [&]<typename... Values>(Values&&... values) {
396+
MaybeBuildField(std::integral_constant<bool, Accessor::in>(), ParamList(), invoke_context,
397+
Make<StructField, Accessor>(params), std::forward<Values>(values)...);
398+
MaybeSetWant(
399+
ParamList(), Priority<1>(), std::forward<Values>(values)..., Make<StructField, Accessor>(params));
400+
};
401+
402+
// Note: The m_values tuple just consists of lvalue and rvalue
403+
// references, so calling std::move doesn't change the tuple, it
404+
// just causes std::apply to call the std::get overload that returns
405+
// && instead of &, so rvalue references are preserved and not
406+
// turned into lvalue references. This allows the BuildField call to
407+
// move from the argument if it is an rvalue reference or was passed
408+
// by value.
409+
std::apply(fun, std::move(m_client_param->m_values));
391410
}
392411

393412
BuildParams(ClientParam* client_param) : m_client_param(client_param) {}
@@ -396,24 +415,15 @@ struct ClientParam
396415

397416
struct ReadResults : IterateFieldsHelper<ReadResults, sizeof...(Types)>
398417
{
399-
template <typename... Args>
400-
void handleField(Args&&... args)
418+
template <typename Results, typename... Params>
419+
void handleField(ClientInvokeContext& invoke_context, Results& results, TypeList<Params...>)
401420
{
402-
callRead<0>(std::forward<Args>(args)...);
403-
}
421+
auto const fun = [&]<typename... Values>(Values&&... values) {
422+
MaybeReadField(std::integral_constant<bool, Accessor::out>(), TypeList<Decay<Params>...>(), invoke_context,
423+
Make<StructField, Accessor>(results), ReadDestUpdate(values)...);
424+
};
404425

405-
template <int I, typename... Args>
406-
auto callRead(Args&&... args) -> std::enable_if_t<(I < sizeof...(Types))>
407-
{
408-
callRead<I + 1>(std::forward<Args>(args)..., std::get<I>(m_client_param->m_values));
409-
}
410-
411-
template <int I, typename Results, typename... Params, typename... Values>
412-
auto callRead(ClientInvokeContext& invoke_context, Results& results, TypeList<Params...>, Values&&... values)
413-
-> std::enable_if_t<I == sizeof...(Types)>
414-
{
415-
MaybeReadField(std::integral_constant<bool, Accessor::out>(), TypeList<Decay<Params>...>(), invoke_context,
416-
Make<StructField, Accessor>(results), ReadDestUpdate(values)...);
426+
std::apply(fun, m_client_param->m_values);
417427
}
418428

419429
ReadResults(ClientParam* client_param) : m_client_param(client_param) {}
@@ -574,7 +584,7 @@ void serverDestroy(Server& server)
574584
//!
575585
//! ProxyClient<ClassName>::M0::Result ProxyClient<ClassName>::methodName(M0::Param<0> arg0, M0::Param<1> arg1) {
576586
//! typename M0::Result result;
577-
//! clientInvoke(*this, &InterfaceName::Client::methodNameRequest, MakeClientParam<...>(arg0), MakeClientParam<...>(arg1), MakeClientParam<...>(result));
587+
//! clientInvoke(*this, &InterfaceName::Client::methodNameRequest, MakeClientParam<...>(M0::Fwd<0>(arg0)), MakeClientParam<...>(M0::Fwd<1>(arg1)), MakeClientParam<...>(result));
578588
//! return result;
579589
//! }
580590
//!
@@ -650,19 +660,14 @@ void clientInvoke(ProxyClient& proxy_client, const GetRequest& get_request, Fiel
650660
//! return value with value of `ret()`. This is useful for avoiding code
651661
//! duplication and branching in generic code that forwards calls to functions.
652662
template <typename Fn, typename Ret>
653-
auto ReplaceVoid(Fn&& fn, Ret&& ret) ->
654-
std::enable_if_t<std::is_same_v<void, decltype(fn())>, decltype(ret())>
663+
auto ReplaceVoid(Fn&& fn, Ret&& ret)
655664
{
656-
fn();
657-
return ret();
658-
}
659-
660-
//! Overload of above for non-void `fn()` case.
661-
template <typename Fn, typename Ret>
662-
auto ReplaceVoid(Fn&& fn, Ret&& ret) ->
663-
std::enable_if_t<!std::is_same_v<void, decltype(fn())>, decltype(fn())>
664-
{
665-
return fn();
665+
if constexpr (std::is_same_v<decltype(fn()), void>) {
666+
fn();
667+
return ret();
668+
} else {
669+
return fn();
670+
}
666671
}
667672

668673
extern std::atomic<int> server_reqs;

src/ipc/libmultiprocess/include/mp/proxy.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ struct ProxyServerCustom : public ProxyServerBase<Interface, Impl>
181181
//!
182182
//! Params - TypeList of C++ ClassName::methodName parameter types
183183
//! Result - Return type of ClassName::method
184-
//! Param<N> - helper to access individual parameters by index number.
184+
//! Param<N> - helper to access individual parameter types by index number.
185+
//! Fwd<N> - helper to forward arguments by index number.
185186
//! Fields - helper alias that appends Result type to the Params typelist if
186187
//! it not void.
187188
template <class Fn>
@@ -199,6 +200,16 @@ struct FunctionTraits<_Result (_Class::*const)(_Params...)>
199200
using Param = typename std::tuple_element<N, std::tuple<_Params...>>::type;
200201
using Fields =
201202
std::conditional_t<std::is_same_v<void, Result>, Params, TypeList<_Params..., _Result>>;
203+
204+
//! Enable perfect forwarding for clientInvoke calls. If parameter is a
205+
//! value type or rvalue reference type, pass it as an rvalue-reference to
206+
//! MakeClientParam and BuildField calls so it can be moved from, and if it
207+
//! is an lvalue reference, pass it an lvalue reference so it won't be moved
208+
//! from. This method does the same thing as std::forward except it takes a
209+
//! parameter number instead of a type as a template argument, so generated
210+
//! code calling this can be less repetitive and verbose.
211+
template <size_t N>
212+
static decltype(auto) Fwd(Param<N>& arg) { return static_cast<Param<N>&&>(arg); }
202213
};
203214

204215
//! Traits class for a proxy method, providing the same

src/ipc/libmultiprocess/include/mp/type-interface.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void CustomBuildField(TypeList<std::shared_ptr<Impl>>,
4444
{
4545
if (value) {
4646
using Interface = typename decltype(output.get())::Calls;
47-
output.set(CustomMakeProxyServer<Interface, Impl>(invoke_context, std::move(value)));
47+
output.set(CustomMakeProxyServer<Interface, Impl>(invoke_context, std::forward<Value>(value)));
4848
}
4949
}
5050

src/ipc/libmultiprocess/include/mp/util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ struct AsyncCallable
183183
template <typename Callable>
184184
AsyncCallable<std::remove_reference_t<Callable>> MakeAsyncCallable(Callable&& callable)
185185
{
186-
return std::move(callable);
186+
return std::forward<Callable>(callable);
187187
}
188188

189189
//! Format current thread name as "{exe_name}-{$pid}/{thread_name}-{$tid}".

src/ipc/libmultiprocess/src/mp/gen.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ static void Generate(kj::StringPtr src_prefix,
215215
cpp_types << "namespace mp {\n";
216216

217217
std::string guard = output_path;
218-
std::transform(guard.begin(), guard.end(), guard.begin(), [](unsigned char c) -> unsigned char {
218+
std::ranges::transform(guard, guard.begin(), [](unsigned char c) -> unsigned char {
219219
if ('0' <= c && c <= '9') return c;
220220
if ('A' <= c && c <= 'Z') return c;
221221
if ('a' <= c && c <= 'z') return c - 'a' + 'A';
@@ -512,10 +512,20 @@ static void Generate(kj::StringPtr src_prefix,
512512

513513
add_accessor(field_name);
514514

515+
std::ostringstream fwd_args;
515516
for (int i = 0; i < field.args; ++i) {
516517
if (argc > 0) client_args << ",";
518+
519+
// Add to client method parameter list.
517520
client_args << "M" << method_ordinal << "::Param<" << argc << "> " << field_name;
518521
if (field.args > 1) client_args << i;
522+
523+
// Add to MakeClientParam argument list using Fwd helper for perfect forwarding.
524+
if (i > 0) fwd_args << ", ";
525+
fwd_args << "M" << method_ordinal << "::Fwd<" << argc << ">(" << field_name;
526+
if (field.args > 1) fwd_args << i;
527+
fwd_args << ")";
528+
519529
++argc;
520530
}
521531
client_invoke << ", ";
@@ -529,13 +539,10 @@ static void Generate(kj::StringPtr src_prefix,
529539
client_invoke << "Accessor<" << base_name << "_fields::" << Cap(field_name) << ", "
530540
<< field_flags.str() << ">>(";
531541

532-
if (field.retval || field.args == 1) {
542+
if (field.retval) {
533543
client_invoke << field_name;
534544
} else {
535-
for (int i = 0; i < field.args; ++i) {
536-
if (i > 0) client_invoke << ", ";
537-
client_invoke << field_name << i;
538-
}
545+
client_invoke << fwd_args.str();
539546
}
540547
client_invoke << ")";
541548

src/ipc/libmultiprocess/src/mp/proxy.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ void EventLoop::startAsyncThread(std::unique_lock<std::mutex>& lock)
277277
}
278278
}
279279

280-
bool EventLoop::done(std::unique_lock<std::mutex>& lock)
280+
bool EventLoop::done(std::unique_lock<std::mutex>& lock) const
281281
{
282282
assert(m_num_clients >= 0);
283283
assert(lock.owns_lock());

src/ipc/libmultiprocess/src/mp/util.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ void ExecProcess(const std::vector<std::string>& args)
137137
}
138138
argv.push_back(nullptr);
139139
if (execvp(argv[0], argv.data()) != 0) {
140-
perror("execlp failed");
140+
perror("execvp failed");
141141
_exit(1);
142142
}
143143
}

0 commit comments

Comments
 (0)