quic/qbox
Loading...
Searching...
No Matches
runonsysc.h
1/*
2 * Copyright (c) 2022-2026 Qualcomm Innovation Center, Inc. All Rights Reserved.
3 * Author: GreenSocs 2022
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8#ifndef RUNONSYSTEMC_H
9#define RUNONSYSTEMC_H
10
11#include <systemc>
12#include <atomic>
13#include <functional>
14#include <future>
15#include <memory>
16#include <mutex>
17#include <queue>
18#include <thread>
19
20namespace gs {
21
22class runonsysc : public sc_core::sc_module
23{
24private:
25 // ============================================================
26 // Core: shared lifetime state
27 // ============================================================
28 struct Core {
29 // --------------------------------------------------------
30 // AsyncJob (private implementation detail)
31 // --------------------------------------------------------
32 struct AsyncJob {
33 using Ptr = std::shared_ptr<AsyncJob>;
34
35 std::function<void()> job;
36
37 std::promise<void> done_promise;
38 std::shared_future<void> done_future;
39
40 std::atomic<bool> cancelled{ false };
41
42 explicit AsyncJob(std::function<void()> j)
43 : job(std::move(j)), done_future(done_promise.get_future().share())
44 {
45 }
46
47 void operator()()
48 {
49 try {
50 if (!cancelled.load(std::memory_order_relaxed)) {
51 job();
52 }
53 done_promise.set_value();
54 } catch (...) {
55 try {
56 done_promise.set_exception(std::current_exception());
57 } catch (...) {
58 // Likely that this is due to jobs being canceled (at cleanup)
59 }
60 }
61 }
62
63 void cancel()
64 {
65 cancelled.store(true, std::memory_order_relaxed);
66 try {
67 done_promise.set_value(); // unblock waiters immediately
68 } catch (...) {
69 // Too late to cancel the job, it already threw itself!
70 }
71 }
72
73 void wait()
74 {
75 done_future.wait();
76 done_future.get(); // rethrows if job threw
77 }
78
79 bool is_cancelled() const { return cancelled.load(std::memory_order_relaxed); }
80 };
81
82 // --------------------------------------------------------
83 // Core state
84 // --------------------------------------------------------
85 std::thread::id thread_id;
86
87 std::queue<typename AsyncJob::Ptr> async_jobs;
88 typename AsyncJob::Ptr running_job;
89 std::mutex async_jobs_mutex;
90
91 async_event jobs_handler_event;
92 std::atomic<bool> running{ true };
93
94 explicit Core(std::thread::id id): thread_id(id), jobs_handler_event(false) {}
95 };
96
97 std::shared_ptr<Core> m_core;
98
99 // ============================================================
100 // SystemC job handler thread
101 // ============================================================
102 void jobs_handler()
103 {
104 auto core = m_core; // hold shared ownership
105 if (!core) return;
106
107 std::unique_lock<std::mutex> lock(core->async_jobs_mutex);
108
109 while (core->running.load(std::memory_order_relaxed)) {
110 while (core->running.load(std::memory_order_relaxed) && !core->async_jobs.empty()) {
111 core->running_job = core->async_jobs.front();
112 core->async_jobs.pop();
113
114 lock.unlock();
115
116 sc_core::sc_unsuspendable();
117 (*core->running_job)();
118 sc_core::sc_suspendable();
119
120 lock.lock();
121 core->running_job.reset();
122 }
123
124 lock.unlock();
125 wait(core->jobs_handler_event);
126 lock.lock();
127 }
128
129 SC_REPORT_WARNING("RunOnSysc", "Stopped");
130 }
131
132 void stop()
133 {
134 auto core = m_core;
135 if (!core) return;
136
137 core->running.store(false, std::memory_order_relaxed);
138 }
139
140 void cancel_all()
141 {
142 auto core = m_core;
143 if (!core) return;
144
145 std::lock_guard<std::mutex> lock(core->async_jobs_mutex);
146
147 while (!core->async_jobs.empty()) {
148 core->async_jobs.front()->cancel();
149 core->async_jobs.pop();
150 }
151
152 if (core->running_job) {
153 core->running_job->cancel();
154 core->running_job.reset();
155 }
156 }
157
158public:
159 // ============================================================
160 // Constructor
161 // ============================================================
162 explicit runonsysc(const sc_core::sc_module_name& n = "run-on-sysc"): sc_module(n)
163 {
164 m_core = std::make_shared<Core>(std::this_thread::get_id());
165 SC_THREAD(jobs_handler);
166 }
167
168 // ============================================================
169 // Destructor
170 // ============================================================
171 ~runonsysc() override
172 {
173 auto core = m_core;
174 if (!core) return;
175
176 stop();
177
178 m_core.reset(); // safe: state lives until last user exits
179 }
180
181 // ============================================================
182 // Public API
183 // ============================================================
184
185 bool is_on_sysc() const
186 {
187 auto core = m_core;
188 return core && (std::this_thread::get_id() == core->thread_id);
189 }
190
191 void end_of_simulation()
192 {
193 auto core = m_core;
194 if (!core) return;
195 stop();
196 cancel_all();
197 }
198
199 void fork_on_systemc(std::function<void()> job_entry) { run_on_sysc(job_entry, false); }
200
211 bool run_on_sysc(std::function<void()> job_entry, bool wait = true)
212 {
213 auto core = m_core; // snapshot lifetime
214 if (!core) return false;
215
216 if (!core->running.load(std::memory_order_relaxed)) return false;
217
218 if (is_on_sysc()) {
219 job_entry();
220 return true;
221 }
222
223 auto job = std::make_shared<typename Core::AsyncJob>(std::move(job_entry));
224
225 {
226 std::lock_guard<std::mutex> lock(core->async_jobs_mutex);
227
228 if (!core->running.load(std::memory_order_relaxed)) return false;
229
230 core->async_jobs.push(job);
231 }
232
233 core->jobs_handler_event.async_notify();
234
235 if (wait) {
236 try {
237 job->wait();
238 } catch (...) {
239 auto old = sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR,
240 sc_core::SC_LOG | sc_core::SC_DISPLAY);
241 SC_REPORT_ERROR("RunOnSysc", "Run on systemc received an unknown exception from job");
242 sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR, old);
243 stop();
244 // Notify the job handler so that it can jump out of it's loop.
245 core->jobs_handler_event.async_notify();
246 return false;
247 }
248
249 return !job->is_cancelled();
250 }
251
252 return true;
253 }
254};
255
256} // namespace gs
257
258#endif // RUNONSYSTEMC_H
Definition target.h:160
Definition async_event.h:22
Definition runonsysc.h:23
bool run_on_sysc(std::function< void()> job_entry, bool wait=true)
Run a job on the SystemC kernel thread.
Definition runonsysc.h:211
Tool which reads a Lua configuration file and sets parameters.
Definition biflow.cc:10
Definition runonsysc.h:32