Skip to content

Commit 6f56dd4

Browse files
Adding thread_utils
Signed-off-by: Mark Burton <[email protected]>
1 parent 5e537b1 commit 6f56dd4

File tree

13 files changed

+781
-6
lines changed

13 files changed

+781
-6
lines changed

CMakeLists.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ FetchContent_Declare(
1212
cpm-cmake
1313
GIT_REPOSITORY ${GITHUB}cpm-cmake/CPM.cmake.git
1414
GIT_SHALLOW True
15-
GIT_TAG v0.31.1
15+
GIT_TAG v0.40.2
1616
)
1717

1818
FetchContent_MakeAvailable(cpm-cmake)
@@ -39,7 +39,10 @@ cpmaddpackage(
3939
NAME report
4040
SOURCE_DIR ${PROJECT_SOURCE_DIR}/report
4141
)
42-
42+
cpmaddpackage(
43+
NAME thread_utils
44+
SOURCE_DIR ${PROJECT_SOURCE_DIR}/thread_utils
45+
)
4346
if("${PROJECT_NAME}" STREQUAL "${CMAKE_PROJECT_NAME}")
4447
add_subdirectory(examples)
4548
if(BUILD_TESTING)

report/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ FetchContent_Declare(
1212
cpm-cmake
1313
GIT_REPOSITORY ${GITHUB}cpm-cmake/CPM.cmake.git
1414
GIT_SHALLOW True
15-
GIT_TAG v0.31.1
15+
GIT_TAG v0.40.2
1616
)
1717

1818
FetchContent_MakeAvailable(cpm-cmake)
@@ -51,7 +51,7 @@ FetchContent_Declare(
5151
GIT_TAG "v1.9.2"
5252
GIT_SHALLOW ON
5353
)
54-
FetchContent_Populate(spdlog_git)
54+
FetchContent_MakeAvailable(spdlog_git)
5555
FetchContent_GetProperties(
5656
spdlog_git
5757
SOURCE_DIR spdlog_git_SRC_DIR

thread_utils/CMakeLists.txt

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
2+
project(thread_utils VERSION 1.0 LANGUAGES CXX C)
3+
4+
set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ standard to build all targets.")
5+
6+
set(GITHUB "https://github.com/" CACHE STRING "github base url")
7+
8+
include(FetchContent)
9+
include(CTest)
10+
11+
FetchContent_Declare(
12+
cpm-cmake
13+
GIT_REPOSITORY ${GITHUB}cpm-cmake/CPM.cmake.git
14+
GIT_SHALLOW True
15+
GIT_TAG v0.40.2
16+
)
17+
18+
FetchContent_MakeAvailable(cpm-cmake)
19+
include(${cpm-cmake_SOURCE_DIR}/cmake/CPM.cmake)
20+
21+
cpmaddpackage("${GITHUB}TheLartians/[email protected]")
22+
23+
cpmaddpackage(
24+
NAME SystemCLanguage
25+
GIT_REPOSITORY ${GITHUB}accellera-official/systemc.git
26+
GIT_SHALLOW True
27+
GIT_TAG main
28+
)
29+
30+
# upstream set INSTALL_NAME_DIR wrong !
31+
if (APPLE)
32+
set_target_properties(
33+
systemc
34+
PROPERTIES
35+
INSTALL_NAME_DIR "@rpath"
36+
)
37+
endif()
38+
39+
40+
add_library(${PROJECT_NAME} INTERFACE)
41+
42+
target_include_directories(
43+
${PROJECT_NAME} INTERFACE
44+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
45+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
46+
)
47+
48+
if(BUILD_TESTING AND ("${PROJECT_NAME}" STREQUAL "${CMAKE_PROJECT_NAME}"))
49+
enable_testing()
50+
add_subdirectory(tests)
51+
endif()
52+
53+
add_library("scp::thread_utils::lib${PROJECT_NAME}" ALIAS ${PROJECT_NAME})
54+
packageproject(
55+
NAME "${PROJECT_NAME}"
56+
VERSION ${PROJECT_VERSION}
57+
NAMESPACE scp
58+
BINARY_DIR ${PROJECT_BINARY_DIR}
59+
INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include
60+
INCLUDE_DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
61+
VERSION_HEADER "${VERSION_HEADER_LOCATION}"
62+
COMPATIBILITY SameMajorVersion
63+
)
64+
install(
65+
TARGETS ${PROJECT_NAME}
66+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
67+
COMPONENT "${PROJECT_NAME}_Runtime"
68+
NAMELINK_COMPONENT "${PROJECT_NAME}_Development"
69+
)

thread_utils/README.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
2+
3+
## Threading Utilities
4+
5+
The library offers the following utilities
6+
7+
# scp::scp_async_event
8+
***NB this could be considered for standardization within the SystemC kernel as sc_async_event***
9+
10+
An ***scp_async_event*** is identical to an sc_event except that it can be notified in a thread safe manner from a different thread. In the same way that an ***sc_event*** may be notified many times, an ***scp_async_event*** makes no guarantee about the number of times the actual event listener is notified, but does guarantee that it will at least be notified after the last time that any of the thread safe notify methods are called.
11+
12+
The ***scp_async_event*** also can be considered as a ***sc_prim_channel***. In addition to the standard ***sc_event*** interface, the ***scp_async_event*** also provides convenience functions to attach and detach the primary channel from the SystemC kernel as a potential source of external events.
13+
14+
*** NOTE ***
15+
An ***scp_async_event*** *MUST* be constructed on the SystemC thread. Failure to do so is an error and will have unexpected consequences.
16+
17+
```cpp
18+
class scp_async_event : public sc_core::sc_prim_channel, public sc_core::sc_event
19+
{
20+
public:
21+
scp_async_event(bool start_attached = true);
22+
void async_attach_suspending();
23+
void async_detach_suspending();
24+
void enable_attach_suspending(bool);
25+
}
26+
```
27+
Hence ***async_attach_suspending*** shall attach the primary channel to the SystemC kernel as a potential source of external events, and will therefore prevent the SystemC kernel from exiting. See ***sc_prim_channel::async_attach_suspending***. Likewise ***async_detach_suspending*** will detach the primary channel, while ***enable_attach_suspending*** shall attach if the boolean argument is true, else it will detach the channel.
28+
29+
On construction by default the channel will be ***attached*** to the kernel, but this may be prevented by passing ***false*** to the constructor.
30+
31+
Notifications of the event from within the same thread as the SystemC kernel shall be treated identically to notifications posted to a normal ***sc_event***. When notified from a different thread the delay posted in the notification of the ***scp_async_event*** shall be respected, but there is no guarantee that the SystemC time will not have advanced by the time the event is posted within the SystemC kernel, so it is recommended that this delay not be used. From a separate thread there is no means to perform an ***immediate*** notification, this will be treated as a delta notification (with SC_ZERO_TIME).
32+
33+
Calling ***triggered()*** from a outside the SystemC kernel thread is an error and an SC_ERROR_REPORT will be generated.
34+
35+
# scp::run_on_systemc
36+
***NB The interface of this class could be considered for standardization within the SystemC kernel***
37+
38+
***run_on_systemc*** provides a convenience class that can be instanced in order to provide the means to execute a ```std::function``` on the SystemC thread in a thread safe manner from another thread.
39+
40+
*** NOTE ***
41+
An instance of the ***run_on_systemc*** module *MUST* be constructed on the SystemC thread. Failure to do so is an error and will have unexpected consequences.
42+
43+
```cpp
44+
class run_on_systemc : public sc_core::sc_module
45+
{
46+
public:
47+
48+
run_on_systemc()
49+
50+
void scp_cancel_pendings();
51+
void scp_fork_on_systemc(std::function<void()> job_entry);
52+
bool scp_run_on_systemc(std::function<void()> job_entry, bool wait = true);
53+
bool scp_is_on_systemc() const;
54+
};
55+
```
56+
57+
In order to run a job on the SystemC kernel thread, ***scp_run_on_systemc*** method should be called with an appropriate ```std::function```. The ***scp_run_on_systemc*** takes an optional argument to wait for the job to be scheduled and executed on SystemC, which defaults to true.
58+
The return status is set to ***true*** if the job has been successfully executed and completed and ***false*** if the job was canceled before it was finished.
59+
60+
If ***run_on_systemc*** is called from within the SystemC thread, then the job is executed immediately (In this case the return status will be ***true***).
61+
62+
The method ***scp_fork_on_systemc*** is a convenience function that calls ***scp_run_on_systemc*** with wait set to false (there is no return status as the job can not be interrupted).
63+
64+
The method ***scp_cancel_pendings*** cancels all pending jobs. Any jobs which are queue'd waiting to be processed by SystemC will be canceled.
65+
66+
67+
# keep_alive
68+
This is a simple ***sc_module*** convenience class which contains an ***scp_async_event*** initialised to attach to the SystemC kernel, and shall therefore ensure that the simulation does not finish. The module provides a convenience function (***finish()***) to detach the event (and therefore allow the simulation to exit).
69+
70+
```cpp
71+
class keep_alive : public sc_core::sc_module
72+
{
73+
public:
74+
scp::async_event keep_alive_event;
75+
76+
keep_alive(sc_core::sc_module_name name): sc_core::sc_module(name) {
77+
keep_alive_event.async_attach_suspending();
78+
}
79+
void finish() {
80+
keep_alive_event.async_detach_suspending();
81+
keep_alive_event.notify();
82+
}
83+
~keep_alive() {}
84+
};
85+
```
86+
87+
88+
89+
# realtimelimiter
90+
An instance of this sc_module will ensure that SystemC time never advances more than realtime (with a granularity of 100ms). Convenience functions to `enable` and `disable` this behavior are provided.
91+
92+
```cpp
93+
SC_MODULE (real_time_limiter) {
94+
public:
95+
void enable();
96+
void disable();
97+
real_time_limiter(const sc_core::sc_module_name& name,
98+
bool autostart = true,
99+
sc_core::sc_time accuracy=sc_core::sc_time(100, sc_core::SC_MS)):
100+
};
101+
```
102+
103+
The constructor, and ***enable*** and ***disable*** funtions must be called from the systemc thread. By default, the ****real_time_limiter*** is constructed to start automatically, with an accuracy of 100ms.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All Rights
3+
* Reserved.
4+
* Author: GreenSocs 2022
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*******************************************************************************/
18+
19+
#ifndef _SCP_ASYNC_EVENT
20+
#define _SCP_ASYNC_EVENT
21+
22+
#include <iostream>
23+
24+
#include <systemc>
25+
#include <tlm>
26+
#include <thread>
27+
#include <mutex>
28+
29+
namespace scp {
30+
class scp_async_event : public sc_core::sc_prim_channel,
31+
public sc_core::sc_event
32+
{
33+
private:
34+
sc_core::sc_time m_delay;
35+
std::thread::id tid;
36+
std::mutex mutex; // Belt and braces
37+
bool outstanding=false;
38+
39+
public:
40+
scp_async_event(bool start_attached = true) {
41+
tid = std::this_thread::get_id();
42+
enable_attach_suspending(start_attached);
43+
}
44+
45+
void async_notify() { notify(); }
46+
47+
void notify() {
48+
if (tid == std::this_thread::get_id()) {
49+
sc_core::sc_event::notify();
50+
} else {
51+
notify(sc_core::SC_ZERO_TIME);
52+
}
53+
}
54+
void notify(double d, sc_core::sc_time_unit u) {
55+
notify(sc_core::sc_time(d, u));
56+
}
57+
void notify(sc_core::sc_time delay) {
58+
if (tid == std::this_thread::get_id()) {
59+
sc_core::sc_event::notify(delay);
60+
} else {
61+
mutex.lock();
62+
m_delay = delay;
63+
outstanding = true;
64+
mutex.unlock();
65+
async_request_update();
66+
}
67+
}
68+
69+
bool triggered() const {
70+
if (tid == std::this_thread::get_id()) {
71+
return sc_core::sc_event::triggered();
72+
} else {
73+
SC_REPORT_ERROR("scp_async_event",
74+
"It is an error to call triggered() from outside "
75+
"the SystemC thread");
76+
}
77+
return false;
78+
}
79+
void async_attach_suspending() {
80+
this->sc_core::sc_prim_channel::async_attach_suspending();
81+
}
82+
83+
void async_detach_suspending() {
84+
this->sc_core::sc_prim_channel::async_detach_suspending();
85+
}
86+
87+
void enable_attach_suspending(bool e) {
88+
e ? this->async_attach_suspending() : this->async_detach_suspending();
89+
}
90+
91+
private:
92+
void update(void) {
93+
mutex.lock();
94+
// we should be in SystemC thread
95+
if (outstanding) {
96+
sc_event::notify(m_delay);
97+
outstanding = false;
98+
}
99+
mutex.unlock();
100+
}
101+
void start_of_simulation() {
102+
// we should be in SystemC thread
103+
if (outstanding) {
104+
request_update();
105+
}
106+
}
107+
};
108+
} // namespace scp
109+
110+
#endif // SCP_ASYNC_EVENT
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*******************************************************************************/
16+
17+
/**
18+
* @class KeepAlive
19+
* @brief this class is used to keep the simulation alive by using an async
20+
* event
21+
*/
22+
#ifndef _SCP_KEEP_ALIVE_H_
23+
#define _SCP_KEEP_ALIVE_H_
24+
25+
#include <systemc>
26+
#include <scp/thread_utils/async_event.h>
27+
28+
namespace scp {
29+
class keep_alive : public sc_core::sc_module
30+
{
31+
public:
32+
scp::scp_async_event keep_alive_event;
33+
34+
keep_alive(sc_core::sc_module_name name): sc_core::sc_module(name) {
35+
keep_alive_event.async_attach_suspending();
36+
}
37+
void finish() {
38+
keep_alive_event.async_detach_suspending();
39+
keep_alive_event.notify();
40+
}
41+
~keep_alive() {}
42+
};
43+
} // namespace scp
44+
45+
#endif

0 commit comments

Comments
 (0)