Skip to content

Commit 749725b

Browse files
frankistcodebot
authored andcommitted
support: replace sfinae for if constexpr in execute_on.h
1 parent a3ce207 commit 749725b

File tree

4 files changed

+131
-199
lines changed

4 files changed

+131
-199
lines changed

include/srsran/support/async/execute_on.h

Lines changed: 75 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -110,143 +110,84 @@ auto defer_to_blocking(TaskExecutor& exec)
110110
/// \param resume_exec task executor where coroutine will resume once the task is run.
111111
/// \param callable task to run.
112112
/// \return awaitable.
113-
template <typename DispatchTaskExecutor,
114-
typename ResumeTaskExecutor,
115-
typename Callable,
116-
typename ResultType = detail::function_return_t<decltype(&std::decay_t<Callable>::operator())>,
117-
std::enable_if_t<not std::is_same<ResultType, void>::value, int> = 0>
118-
auto offload_to_executor(DispatchTaskExecutor& dispatch_exec, ResumeTaskExecutor& resume_exec, Callable&& callable)
113+
template <typename DispatchTaskExecutor, typename ResumeTaskExecutor, typename Callable>
114+
auto try_offload_to_executor(DispatchTaskExecutor& dispatch_exec, ResumeTaskExecutor& resume_exec, Callable&& callable)
119115
{
120-
struct task_executor_offloader {
121-
task_executor_offloader(DispatchTaskExecutor& dispatch_exec_,
122-
ResumeTaskExecutor& resume_exec_,
123-
Callable callable_) :
124-
dispatch_exec(dispatch_exec_), resume_exec(resume_exec_), task(std::forward<Callable>(callable_))
125-
{
126-
}
127-
128-
bool await_ready() noexcept { return false; }
129-
130-
void await_suspend(coro_handle<> suspending_coro)
131-
{
132-
continuation = suspending_coro;
133-
bool dispatched1 = dispatch_exec.execute([this]() mutable {
134-
result = task();
135-
bool dispatched2 = resume_exec.execute([this]() { continuation.resume(); });
136-
srsran_assert(dispatched2, "Failed to dispatch task");
137-
});
138-
srsran_assert(dispatched1, "Failed to dispatch task");
139-
}
140-
141-
ResultType await_resume() { return result; }
142-
143-
task_executor_offloader& get_awaiter() { return *this; }
144-
145-
private:
146-
DispatchTaskExecutor& dispatch_exec;
147-
ResumeTaskExecutor& resume_exec;
148-
Callable task;
149-
ResultType result;
150-
coro_handle<> continuation;
151-
};
152-
return task_executor_offloader{dispatch_exec, resume_exec, std::forward<Callable>(callable)};
153-
}
154-
155-
template <typename DispatchTaskExecutor,
156-
typename ResumeTaskExecutor,
157-
typename Callable,
158-
typename ResultType = detail::function_return_t<decltype(&std::decay_t<Callable>::operator())>,
159-
std::enable_if_t<std::is_same<ResultType, void>::value, int> = 0>
160-
auto offload_to_executor(DispatchTaskExecutor& dispatch_exec, ResumeTaskExecutor& resume_exec, Callable&& callable)
161-
{
162-
struct task_executor_offloader {
163-
task_executor_offloader(DispatchTaskExecutor& dispatch_exec_,
164-
ResumeTaskExecutor& resume_exec_,
165-
Callable callable_) :
166-
dispatch_exec(dispatch_exec_), resume_exec(resume_exec_), task(std::forward<Callable>(callable_))
167-
{
168-
}
169-
170-
bool await_ready() noexcept { return false; }
171-
172-
void await_suspend(coro_handle<> suspending_coro)
173-
{
174-
continuation = suspending_coro;
175-
dispatch_exec.execute([this]() mutable {
176-
task();
177-
resume_exec.execute([this]() { continuation.resume(); });
178-
});
179-
}
180-
181-
void await_resume() {}
182-
183-
task_executor_offloader& get_awaiter() { return *this; }
184-
185-
private:
186-
DispatchTaskExecutor& dispatch_exec;
187-
ResumeTaskExecutor& resume_exec;
188-
Callable task;
189-
coro_handle<> continuation;
190-
};
191-
192-
return task_executor_offloader{dispatch_exec, resume_exec, std::forward<Callable>(callable)};
193-
}
194-
195-
/// \brief Returns an async_task<void> that runs a given invocable task in a \c dispatch_exec executor, and once the
196-
/// task is complete, it resumes the suspended coroutine in a \c return_exec executor.
197-
template <typename DispatchTaskExecutor,
198-
typename CurrentTaskExecutor,
199-
typename Callable,
200-
typename ReturnType = detail::function_return_t<decltype(&Callable::operator())>>
201-
std::enable_if_t<std::is_same<ReturnType, void>::value, async_task<void>>
202-
execute_and_continue_on_blocking(DispatchTaskExecutor& dispatch_exec,
203-
CurrentTaskExecutor& return_exec,
204-
Callable&& callable)
205-
{
206-
return launch_async([&return_exec, &dispatch_exec, task = std::forward<Callable>(callable)](
207-
coro_context<async_task<void>>& ctx) mutable {
208-
CORO_BEGIN(ctx);
209-
210-
// Dispatch execution context switch.
211-
CORO_AWAIT(execute_on_blocking(dispatch_exec));
212-
213-
// Run task.
214-
task();
215-
216-
// Continuation in the original executor.
217-
CORO_AWAIT(execute_on_blocking(return_exec));
218-
219-
CORO_RETURN();
220-
});
221-
}
222-
223-
/// \brief Returns an async_task<ReturnType> that runs a given invocable task in a \c dispatch_exec executor, and once
224-
/// the task is complete, it resumes the suspended coroutine in a \c return_exec executor.
225-
template <typename DispatchTaskExecutor,
226-
typename CurrentTaskExecutor,
227-
typename Callable,
228-
typename ReturnType = detail::function_return_t<decltype(&Callable::operator())>>
229-
std::enable_if_t<not std::is_same<ReturnType, void>::value, async_task<ReturnType>>
230-
execute_and_continue_on_blocking(DispatchTaskExecutor& dispatch_exec,
231-
CurrentTaskExecutor& return_exec,
232-
Callable&& callable)
233-
{
234-
ReturnType ret{};
235-
return launch_async([&return_exec, &dispatch_exec, task = std::forward<Callable>(callable), ret](
236-
coro_context<async_task<ReturnType>>& ctx) mutable {
237-
CORO_BEGIN(ctx);
238-
239-
// Dispatch execution context switch.
240-
CORO_AWAIT(execute_on_blocking(dispatch_exec));
241-
242-
// Run task.
243-
ret = task();
116+
using result_type = detail::function_return_t<decltype(&std::decay_t<Callable>::operator())>;
117+
118+
if constexpr (std::is_same_v<result_type, void>) {
119+
// void return case.
120+
121+
struct task_executor_offloader {
122+
task_executor_offloader(DispatchTaskExecutor& dispatch_exec_,
123+
ResumeTaskExecutor& resume_exec_,
124+
Callable callable_) :
125+
dispatch_exec(dispatch_exec_), resume_exec(resume_exec_), task(std::forward<Callable>(callable_))
126+
{
127+
}
128+
129+
bool await_ready() noexcept { return false; }
130+
131+
void await_suspend(coro_handle<> suspending_coro)
132+
{
133+
continuation = suspending_coro;
134+
dispatch_exec.execute([this]() mutable {
135+
task();
136+
resume_exec.execute([this]() { continuation.resume(); });
137+
});
138+
}
139+
140+
void await_resume() {}
141+
142+
task_executor_offloader& get_awaiter() { return *this; }
143+
144+
private:
145+
DispatchTaskExecutor& dispatch_exec;
146+
ResumeTaskExecutor& resume_exec;
147+
Callable task;
148+
coro_handle<> continuation;
149+
};
244150

245-
// Continuation in the original executor.
246-
CORO_AWAIT(execute_on_blocking(return_exec));
151+
return task_executor_offloader{dispatch_exec, resume_exec, std::forward<Callable>(callable)};
152+
153+
} else {
154+
// non-void return case.
155+
156+
struct task_executor_offloader {
157+
task_executor_offloader(DispatchTaskExecutor& dispatch_exec_,
158+
ResumeTaskExecutor& resume_exec_,
159+
Callable callable_) :
160+
dispatch_exec(dispatch_exec_), resume_exec(resume_exec_), task(std::forward<Callable>(callable_))
161+
{
162+
}
163+
164+
bool await_ready() noexcept { return false; }
165+
166+
void await_suspend(coro_handle<> suspending_coro)
167+
{
168+
continuation = suspending_coro;
169+
bool dispatched1 = dispatch_exec.execute([this]() mutable {
170+
result = task();
171+
bool dispatched2 = resume_exec.execute([this]() { continuation.resume(); });
172+
srsran_assert(dispatched2, "Failed to dispatch task");
173+
});
174+
srsran_assert(dispatched1, "Failed to dispatch task");
175+
}
176+
177+
result_type await_resume() { return result; }
178+
179+
task_executor_offloader& get_awaiter() { return *this; }
180+
181+
private:
182+
DispatchTaskExecutor& dispatch_exec;
183+
ResumeTaskExecutor& resume_exec;
184+
Callable task;
185+
result_type result;
186+
coro_handle<> continuation;
187+
};
247188

248-
CORO_RETURN(ret);
249-
});
189+
return task_executor_offloader{dispatch_exec, resume_exec, std::forward<Callable>(callable)};
190+
}
250191
}
251192

252193
} // namespace srsran

include/srsran/support/async/execute_on_blocking.h

Lines changed: 50 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -95,74 +95,65 @@ auto defer_on_blocking(TaskExecutor& exec, timer_manager& timers, OnFailureToDis
9595
exec, timers, std::forward<OnFailureToDispatch>(on_failure));
9696
}
9797

98-
/// \brief Returns an async_task<void> that runs a given invocable task in a \c dispatch_exec executor, and once the
99-
/// task is complete, it resumes the suspended coroutine in a \c return_exec executor.
98+
/// \brief Returns an async_task<ReturnType> that runs a given invocable task in a \c dispatch_exec executor, and once
99+
/// the task is complete, it resumes the suspended coroutine in a \c return_exec executor.
100100
template <typename DispatchTaskExecutor,
101101
typename CurrentTaskExecutor,
102102
typename Callable,
103-
typename OnFailureToDispatch = noop_operation,
104-
typename ReturnType = detail::function_return_t<decltype(&Callable::operator())>>
105-
std::enable_if_t<std::is_same_v<ReturnType, void>, async_task<void>>
106-
execute_and_continue_on_blocking(DispatchTaskExecutor& dispatch_exec,
107-
CurrentTaskExecutor& return_exec,
108-
timer_manager& timers,
109-
Callable&& callable,
110-
OnFailureToDispatch&& on_failure = noop_operation{})
103+
typename OnFailureToDispatch = noop_operation>
104+
auto execute_and_continue_on_blocking(DispatchTaskExecutor& dispatch_exec,
105+
CurrentTaskExecutor& return_exec,
106+
timer_manager& timers,
107+
Callable&& callable,
108+
OnFailureToDispatch&& on_failure = noop_operation{})
111109
{
112-
return launch_async([&return_exec,
113-
&dispatch_exec,
114-
task = std::forward<Callable>(callable),
115-
on_failure = std::forward<OnFailureToDispatch>(on_failure),
116-
&timers](coro_context<async_task<void>>& ctx) mutable {
117-
CORO_BEGIN(ctx);
110+
using return_type = detail::function_return_t<decltype(&Callable::operator())>;
118111

119-
// Dispatch execution context switch.
120-
CORO_AWAIT(execute_on_blocking(dispatch_exec, timers, on_failure));
112+
if constexpr (std::is_same_v<return_type, void>) {
113+
// async_task<void> case.
121114

122-
// Run task.
123-
task();
115+
return launch_async([&return_exec,
116+
&dispatch_exec,
117+
task = std::forward<Callable>(callable),
118+
on_failure = std::forward<OnFailureToDispatch>(on_failure),
119+
&timers](coro_context<async_task<void>>& ctx) mutable {
120+
CORO_BEGIN(ctx);
124121

125-
// Continuation in the original executor.
126-
CORO_AWAIT(execute_on_blocking(return_exec, timers, on_failure));
122+
// Dispatch execution context switch.
123+
CORO_AWAIT(execute_on_blocking(dispatch_exec, timers, on_failure));
127124

128-
CORO_RETURN();
129-
});
130-
}
125+
// Run task.
126+
task();
131127

132-
/// \brief Returns an async_task<ReturnType> that runs a given invocable task in a \c dispatch_exec executor, and once
133-
/// the task is complete, it resumes the suspended coroutine in a \c return_exec executor.
134-
template <typename DispatchTaskExecutor,
135-
typename CurrentTaskExecutor,
136-
typename Callable,
137-
typename OnFailureToDispatch = noop_operation,
138-
typename ReturnType = detail::function_return_t<decltype(&Callable::operator())>>
139-
std::enable_if_t<not std::is_same_v<ReturnType, void>, async_task<ReturnType>>
140-
execute_and_continue_on_blocking(DispatchTaskExecutor& dispatch_exec,
141-
CurrentTaskExecutor& return_exec,
142-
timer_manager& timers,
143-
Callable&& callable,
144-
OnFailureToDispatch&& on_failure = noop_operation{})
145-
{
146-
ReturnType ret{};
147-
return launch_async([&return_exec,
148-
&dispatch_exec,
149-
task = std::forward<Callable>(callable),
150-
on_failure = std::forward<OnFailureToDispatch>(on_failure),
151-
&timers,
152-
ret](coro_context<async_task<ReturnType>>& ctx) mutable {
153-
CORO_BEGIN(ctx);
154-
155-
// Dispatch execution context switch.
156-
CORO_AWAIT(execute_on_blocking(dispatch_exec, timers, on_failure));
157-
158-
// Run task.
159-
ret = task();
160-
161-
// Continuation in the original executor.
162-
CORO_AWAIT(execute_on_blocking(return_exec, timers, on_failure));
163-
164-
CORO_RETURN(ret);
165-
});
128+
// Continuation in the original executor.
129+
CORO_AWAIT(execute_on_blocking(return_exec, timers, on_failure));
130+
131+
CORO_RETURN();
132+
});
133+
134+
} else {
135+
// async_task<return_type> case.
136+
137+
return launch_async([&return_exec,
138+
&dispatch_exec,
139+
task = std::forward<Callable>(callable),
140+
on_failure = std::forward<OnFailureToDispatch>(on_failure),
141+
&timers,
142+
ret = return_type{}](coro_context<async_task<return_type>>& ctx) mutable {
143+
CORO_BEGIN(ctx);
144+
145+
// Dispatch execution context switch.
146+
CORO_AWAIT(execute_on_blocking(dispatch_exec, timers, on_failure));
147+
148+
// Run task.
149+
ret = task();
150+
151+
// Continuation in the original executor.
152+
CORO_AWAIT(execute_on_blocking(return_exec, timers, on_failure));
153+
154+
CORO_RETURN(ret);
155+
});
156+
}
166157
}
167158

168159
} // namespace srsran

lib/cu_up/cu_up_manager_impl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*/
1010

1111
#include "cu_up_manager_impl.h"
12-
#include "srsran/support/async/execute_on.h"
12+
#include "srsran/support/async/execute_on_blocking.h"
1313

1414
using namespace srsran;
1515
using namespace srs_cu_up;
@@ -111,7 +111,7 @@ cu_up_manager_impl::handle_bearer_context_modification_request(const e1ap_bearer
111111
});
112112
}
113113
return execute_and_continue_on_blocking(
114-
ue_ctxt->ue_exec_mapper->ctrl_executor(), cfg.exec_mapper->ctrl_executor(), [this, ue_ctxt, msg]() {
114+
ue_ctxt->ue_exec_mapper->ctrl_executor(), cfg.exec_mapper->ctrl_executor(), *cfg.timers, [this, ue_ctxt, msg]() {
115115
return handle_bearer_context_modification_request_impl(*ue_ctxt, msg);
116116
});
117117
}

tests/unittests/support/async_exec_test.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@ void test_offload_exec()
7373
launch_async([&exec0, exec1, exec2, &inc_count, &worker0](coro_context<eager_async_task<int>>& ctx) mutable {
7474
CORO_BEGIN(ctx);
7575
inc_count();
76-
CORO_AWAIT(offload_to_executor(exec1, exec0, inc_count));
77-
CORO_AWAIT(offload_to_executor(exec2, exec0, inc_count));
78-
CORO_AWAIT(offload_to_executor(exec1, exec0, inc_count));
79-
CORO_AWAIT(offload_to_executor(exec2, exec0, inc_count));
76+
CORO_AWAIT(try_offload_to_executor(exec1, exec0, inc_count));
77+
CORO_AWAIT(try_offload_to_executor(exec2, exec0, inc_count));
78+
CORO_AWAIT(try_offload_to_executor(exec1, exec0, inc_count));
79+
CORO_AWAIT(try_offload_to_executor(exec2, exec0, inc_count));
8080
worker0.request_stop(); // as we are in worker0, the cancel command is only processed after the return
8181
CORO_RETURN(inc_count());
8282
});

0 commit comments

Comments
 (0)