bmv2
Designing your own switch target with bmv2
stateful.h
Go to the documentation of this file.
1 /* Copyright 2013-present Barefoot Networks, Inc.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 /*
17  * Antonin Bas (antonin@barefootnetworks.com)
18  *
19  */
20 
34 
35 #ifndef BM_BM_SIM_STATEFUL_H_
36 #define BM_BM_SIM_STATEFUL_H_
37 
38 #include <functional>
39 #include <mutex>
40 #include <string>
41 #include <unordered_set>
42 #include <unordered_map>
43 #include <vector>
44 
45 #include <boost/thread/locks.hpp> // for boost::lock
46 
47 #include "bignum.h"
48 #include "data.h"
49 #include "named_p4object.h"
50 #include "short_alloc.h"
51 
52 namespace bm {
53 
54 class RegisterArray; // forward declaration
55 
58 class Register : public Data {
59  public:
60  enum RegisterErrorCode {
61  SUCCESS = 0,
62  INVALID_REGISTER_NAME,
63  INVALID_INDEX,
64  ERROR
65  };
66 
67  public:
68  Register(int nbits, const RegisterArray *register_array);
69 
70  void export_bytes() override;
71 
72  private:
73  Bignum mask{1};
74  // keep a pointer to parent RegisterArray so that export_bytes() can notify
75  // write operations
76  const RegisterArray *register_array;
77 };
78 
79 using register_array_id_t = p4object_id_t;
80 
92 class RegisterArray : public NamedP4Object {
93  friend class RegisterSync;
94  friend class Register;
95 
96  public:
97  using iterator = std::vector<Register>::iterator;
98  using const_iterator = std::vector<Register>::const_iterator;
99 
100  using UniqueLock = std::unique_lock<std::mutex>;
101 
104  using Notifier = std::function<void(size_t idx)>;
105 
106  RegisterArray(const std::string &name, p4object_id_t id,
107  size_t size, int bitwidth);
108 
110  Register &operator[](size_t idx) {
111  assert(idx < size());
112  return registers[idx];
113  }
114 
116  const Register &operator[](size_t idx) const {
117  assert(idx < size());
118  return registers[idx];
119  }
120 
123  Register &at(size_t idx) {
124  return registers.at(idx);
125  }
126 
128  const Register &at(size_t idx) const {
129  return registers.at(idx);
130  }
131 
132  // iterators
133 
135  iterator begin() { return registers.begin(); }
136 
138  const_iterator begin() const { return registers.begin(); }
139 
141  iterator end() { return registers.end(); }
142 
144  const_iterator end() const { return registers.end(); }
145 
148  size_t size() const { return registers.size(); }
149 
150  void reset_state();
151 
156  void register_notifier(Notifier notifier);
157 
163  UniqueLock unique_lock() const { return UniqueLock(m_mutex); }
164  // NOLINTNEXTLINE(runtime/references)
165  void unlock(UniqueLock &lock) const { lock.unlock(); }
166 
167  private:
168  void notify(const Register &reg) const;
169 
170  std::vector<Register> registers{};
171  mutable std::mutex m_mutex{};
172  int bitwidth{};
173  std::vector<Notifier> notifiers{};
174 };
175 
176 
177 // This class was added to provide some measure of concurrency support for
178 // register accesses. Every time an action is executed, this action is given
179 // exclusive access to all the registers it is referring to. Same thing for a
180 // parse state.
181 class RegisterSync {
182  public:
183  using Lock = RegisterArray::UniqueLock;
184 
185  template <size_t NumLocks = 4>
186  using LockVector = std::vector<
187  Lock, ::detail::short_alloc<Lock, NumLocks * sizeof(Lock), alignof(Lock)> >;
188 
189  struct RegisterLocks {
190  LockVector<>::allocator_type::arena_type a;
191  LockVector<> v{a};
192  };
193 
194  void add_register_array(const RegisterArray *register_array);
195 
196  void merge_from(const RegisterSync &other);
197 
198  // tried NRVO, but RegisterLocks not movable
199  void lock(RegisterLocks *RL) const {
200  for (auto m : mutexes) RL->v.emplace_back(*m, std::defer_lock);
201  boost::lock(RL->v.begin(), RL->v.end());
202  }
203 
204  private:
205  mutable std::vector<std::mutex *> mutexes{};
206  std::unordered_set<const RegisterArray *> register_arrays{};
207 };
208 
209 } // namespace bm
210 
211 #endif // BM_BM_SIM_STATEFUL_H_
bm::NamedP4Object
Definition: named_p4object.h:39
bm::RegisterArray::end
const_iterator end() const
NC.
Definition: stateful.h:144
bm::RegisterArray::begin
const_iterator begin() const
NC.
Definition: stateful.h:138
bm::RegisterArray::end
iterator end()
NC.
Definition: stateful.h:141
bm::RegisterArray::Notifier
std::function< void(size_t idx)> Notifier
Definition: stateful.h:104
bm::Register
Definition: stateful.h:58
named_p4object.h
bm::RegisterArray::register_notifier
void register_notifier(Notifier notifier)
bm::RegisterArray
Definition: stateful.h:92
bm::RegisterArray::unique_lock
UniqueLock unique_lock() const
Definition: stateful.h:163
bm::RegisterArray::operator[]
Register & operator[](size_t idx)
Access the register at position idx, asserts if bad idx.
Definition: stateful.h:110
bm::RegisterArray::at
Register & at(size_t idx)
Definition: stateful.h:123
bm::RegisterArray::operator[]
const Register & operator[](size_t idx) const
Access the register at position idx, asserts if bad idx.
Definition: stateful.h:116
bm::RegisterArray::begin
iterator begin()
NC.
Definition: stateful.h:135
bm::RegisterArray::at
const Register & at(size_t idx) const
Definition: stateful.h:128
bm::RegisterArray::size
size_t size() const
Definition: stateful.h:148