scc  2024.06
SystemC components library
ordered_semaphore.cpp
1 /*******************************************************************************
2  * Copyright 2019 MINRES Technologies GmbH
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 #include "ordered_semaphore.h"
18 #include "report.h"
19 #include "sysc/communication/sc_communication_ids.h"
20 #include "sysc/kernel/sc_wait.h"
21 #include <util/strprintf.h>
22 
23 namespace scc {
24 
25 using namespace sc_core;
26 
27 // ----------------------------------------------------------------------------
28 // CLASS : sc_semaphore
29 //
30 // The sc_semaphore primitive channel class.
31 // ----------------------------------------------------------------------------
32 
33 // error reporting
34 namespace {
35 auto gen_unique_event_name(const char* modifier) -> std::string {
36  auto str = std::string("$$$$kernel_event$$$$_") + "_" + modifier;
37  return std::string(sc_core::sc_gen_unique_name(str.c_str(), false));
38 }
39 } // namespace
40 
42  if(typeid(*this) == typeid(ordered_semaphore)) {
43  auto diff = static_cast<int>(capacity) - static_cast<int>(c);
44  capacity = c;
45  value -= diff;
46  if(value > 0)
47  free_evt.notify(sc_core::SC_ZERO_TIME);
48  } else {
49  SCCWARN(SCMOD) << "cannot resize fixed size ordered semaphore";
50  }
51 }
52 
53 void ordered_semaphore::trace(sc_core::sc_trace_file* tf) const {
54  if(value_traceable) {
55  value_ref->trace(tf);
56  }
57 }
58 
59 void ordered_semaphore::report_error(const char* id, const char* add_msg) const {
60  auto msg = add_msg ? util::strprintf("semaphore '%s'", name()) : util::strprintf("%s: semaphore '%s'", add_msg, name());
61  SC_REPORT_ERROR(id, msg.c_str());
62 }
63 
64 // constructors
66 : sc_core::sc_object(sc_core::sc_gen_unique_name("semaphore"))
67 , free_evt(gen_unique_event_name("free_event").c_str())
68 , value(init_value_)
69 , capacity(init_value_) {
70  if(value < 0) {
71  report_error(sc_core::SC_ID_INVALID_SEMAPHORE_VALUE_);
72  }
73 }
74 
75 ordered_semaphore::ordered_semaphore(const char* name_, unsigned init_value_, bool value_traceable)
76 : sc_object(name_)
77 , free_evt(gen_unique_event_name("free_event").c_str())
78 , value(init_value_)
79 , capacity(init_value_)
80 , value_traceable(value_traceable) {
81  if(value < 0) {
82  report_error(sc_core::SC_ID_INVALID_SEMAPHORE_VALUE_);
83  }
84  if(value_traceable)
85  value_ref.reset(new scc::sc_ref_variable<int>(std::string(basename()) + "_count", value, true));
86 }
87 
88 // interface methods
89 
90 // lock (take) the semaphore, block if not available
91 auto ordered_semaphore::wait(unsigned priority) -> int {
92  queue.at(priority).push_back(sc_core::sc_get_current_process_handle());
93  while(in_use()) {
94  sc_core::wait(free_evt);
95  }
96  --value;
97  if(value_ref)
98  value_ref->notify();
99  return value;
100 }
101 
102 // lock (take) the semaphore, return -1 if not available
103 
105  if(in_use()) {
106  return -1;
107  }
108  --value;
109  if(value_ref)
110  value_ref->notify();
111  return value;
112 }
113 
114 // unlock (give) the semaphore
115 
116 auto ordered_semaphore::post() -> int {
117  if(capacity && value == capacity) {
118  SCCWARN(SCMOD) << "post() called on entirely free semaphore!";
119  } else {
120  ++value;
121  if(value_ref)
122  value_ref->notify();
123  }
124  if(value > 0)
125  free_evt.notify(sc_core::SC_ZERO_TIME);
126  return value;
127 }
128 
129 } // namespace scc
The ordered_semaphore primitive channel class.
void trace(sc_core::sc_trace_file *tf) const override
adds internal variables to trace
int post() override
unlock (give) the semaphore
int wait() override
lock (take) the semaphore, block if not available
void set_capacity(unsigned capacity)
change the capacity
ordered_semaphore(unsigned init_value=1)
constructor of an un-named semaphore
int trywait() override
lock (take) the semaphore, return -1 if not available
SCC TLM utilities.
SCC common utilities.
Definition: bit_field.h:30
std::string strprintf(const std::string format,...)
allocate and print to a string buffer
Definition: strprintf.h:35
the sc_ref_variable for a particular plain data type. This marks an existing C++ variable as discover...
Definition: sc_variable.h:426