quic/qbox
Loading...
Searching...
No Matches
runonsysc.h
1/*
2 * Copyright (c) 2022-2023 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 <thread>
12#include <mutex>
13#include <condition_variable>
14#include <queue>
15#include <future>
16
17#include <async_event.h>
18#include <uutils.h>
19
20namespace gs {
21class runonsysc : public sc_core::sc_module
22{
23protected:
25 {
26 public:
27 using Ptr = std::shared_ptr<AsyncJob>;
28
29 private:
30 std::packaged_task<void()> m_task;
31
32 bool m_cancelled = false;
33
34 void run_job() { m_task(); }
35
36 public:
37 AsyncJob(std::function<void()>&& job): m_task(job) {}
38
39 AsyncJob(std::function<void()>& job): m_task(job) {}
40
41 AsyncJob() = delete;
42 AsyncJob(const AsyncJob&) = delete;
43
44 void operator()() { run_job(); }
45
52 void cancel()
53 {
54 m_cancelled = true;
55 m_task.reset();
56 }
57
58 void wait()
59 {
60 auto future = m_task.get_future();
61
62 future.wait();
63
64 if (!m_cancelled) {
65 future.get();
66 }
67 }
68
69 bool is_cancelled() const { return m_cancelled; }
70 };
71
72 std::thread::id m_thread_id;
73
74 /* Async job queue */
75 std::queue<AsyncJob::Ptr> m_async_jobs;
76 AsyncJob::Ptr m_running_job;
77 std::mutex m_async_jobs_mutex;
78
79 async_event m_jobs_handler_event;
80 std::atomic<bool> running = true;
81
82 // Process inside a thread incase the job calls wait
83 void jobs_handler()
84 {
85 std::unique_lock<std::mutex> lock(m_async_jobs_mutex);
86 running = true;
87 for (; running;) {
88 while (!m_async_jobs.empty()) {
89 m_running_job = m_async_jobs.front();
90 m_async_jobs.pop();
91
92 lock.unlock();
93 sc_core::sc_unsuspendable(); // a wait in the job will cause systemc time to advance
94 (*m_running_job)();
95 sc_core::sc_suspendable();
96 lock.lock();
97
98 m_running_job.reset();
99 }
100 lock.unlock();
101 wait(m_jobs_handler_event);
102 lock.lock();
103 }
104 SC_REPORT_WARNING("RunOnSysc", "Stopped");
105 sc_core::sc_stop();
106 }
107
108 void cancel_pendings_locked()
109 {
110 while (!m_async_jobs.empty()) {
111 m_async_jobs.front()->cancel();
112 m_async_jobs.pop();
113 }
114 }
115
116public:
117 runonsysc(const sc_core::sc_module_name& n = sc_core::sc_module_name("run-on-sysc"))
118 : sc_module(n)
119 , m_thread_id(std::this_thread::get_id())
120 , m_jobs_handler_event(false) // starve if no more jobs provided
121 {
122 SC_THREAD(jobs_handler);
123 }
124
132 {
133 std::lock_guard<std::mutex> lock(m_async_jobs_mutex);
134
135 cancel_pendings_locked();
136 }
137
148 {
149 std::lock_guard<std::mutex> lock(m_async_jobs_mutex);
150
151 cancel_pendings_locked();
152
153 if (m_running_job) {
154 m_running_job->cancel();
155 m_running_job.reset();
156 }
157 }
158 void stop()
159 {
160 running = false;
161 m_jobs_handler_event.async_notify();
162 }
163 void end_of_simulation()
164 {
165 running = false;
166 cancel_all();
167 }
168
169 void fork_on_systemc(std::function<void()> job_entry) { run_on_sysc(job_entry, false); }
170
181 bool run_on_sysc(std::function<void()> job_entry, bool wait = true)
182 {
183 if (!running) return false;
184 if (is_on_sysc()) {
185 job_entry();
186 return true;
187 } else {
188 AsyncJob::Ptr job(new AsyncJob(job_entry));
189
190 {
191 std::lock_guard<std::mutex> lock(m_async_jobs_mutex);
192 m_async_jobs.push(job);
193 }
194
195 m_jobs_handler_event.async_notify();
196
197 if (wait) {
198 /* Wait for job completion */
199 try {
200 job->wait();
201 } catch (std::runtime_error const& e) {
202 /* Report unknown runtime errors, without causing a futher excetion */
203 auto old = sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR,
204 sc_core::SC_LOG | sc_core::SC_DISPLAY);
206 "RunOnSysc",
207 ("Run on systemc received a runtime error from job: " + std::string(e.what())).c_str());
208 sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR, old);
209 stop();
210 return false;
211 } catch (const std::exception& exc) {
212 if (sc_core::sc_report_handler::get_count(sc_core::SC_ERROR) == 0) {
213 /* Report exceptions that were not caused by SC_ERRORS (which have already been reported)*/
214 auto old = sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR,
215 sc_core::SC_LOG | sc_core::SC_DISPLAY);
217 "RunOnSysc",
218 ("Run on systemc received an exception from job: " + std::string(exc.what())).c_str());
219 sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR, old);
220 }
221 stop();
222 return false;
223 } catch (...) {
224 auto old = sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR,
225 sc_core::SC_LOG | sc_core::SC_DISPLAY);
226 SC_REPORT_ERROR("RunOnSysc", "Run on systemc received an unknown exception from job");
227 sc_core::sc_report_handler::set_actions(sc_core::SC_ERROR, old);
228 stop();
229 return false;
230 }
231
232 return !job->is_cancelled();
233 }
234
235 return true;
236 }
237 }
238
242 bool is_on_sysc() const { return std::this_thread::get_id() == m_thread_id; }
243};
244} // namespace gs
245
246#endif // RUNONSYSTEMC_H
Definition target.h:160
Definition runonsysc.h:25
void cancel()
Cancel a job.
Definition runonsysc.h:52
Definition runonsysc.h:22
void cancel_pendings()
Cancel all pending jobs.
Definition runonsysc.h:131
void cancel_all()
Cancel all pending and running jobs.
Definition runonsysc.h:147
bool run_on_sysc(std::function< void()> job_entry, bool wait=true)
Run a job on the SystemC kernel thread.
Definition runonsysc.h:181
bool is_on_sysc() const
Definition runonsysc.h:242
Tool which reads a Lua configuration file and sets parameters.
Definition biflow.cc:10