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