Tervel  1.0.0
A collection of wait-free containers and algorithms.
write_op.h
Go to the documentation of this file.
1 /*
2 The MIT License (MIT)
3 
4 Copyright (c) 2015 University of Central Florida's Computer Software Engineering
5 Scalable & Secure Systems (CSE - S3) Lab
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 THE SOFTWARE.
24 */
25 #ifndef __TERVEL_CONTAINERS_WF_VECTOR_WRITE_OP_H
26 #define __TERVEL_CONTAINERS_WF_VECTOR_WRITE_OP_H
27 
28 
29 #include <tervel/util/info.h>
30 #include <tervel/util/descriptor.h>
34 
35 
36 #include <tervel/containers/wf/vector/vector.hpp>
37 
38 namespace tervel {
39 namespace containers {
40 namespace wf {
41 namespace vector {
42 
43 template<typename T>
45 
46 
47 template<typename T>
49  public:
50  WriteOp(Vector<T> *vec, size_t idx, T expected, T val)
51  : vec_(vec)
52  , idx_(idx)
53  , expected_(expected)
54  , new_val_(val) {}
55 
57  WriteHelper<T> * c_fail_pointer_ =
58  reinterpret_cast<WriteHelper<T> *>(~0x1L);
59  WriteHelper<T> * temp = helper_.load();
60  assert(temp != nullptr);
61  if (temp != c_fail_pointer_) {
63  }
64  }
65 
66  void help_complete() {
67  tervel::tl_control_word = reinterpret_cast< std::atomic<void *>*>(&helper_);
68  WriteHelper<T> * c_fail_pointer_ =
69  reinterpret_cast<WriteHelper<T> *>(~0x1L);
70 
71  if (idx_ < vec_->size()) {
72  std::atomic<T> *spot = vec_->internal_array.get_spot(idx_, false);
73 
74  while (helper_.load() == nullptr) {
75  T cvalue = spot->load();
76 
77  if (cvalue == Vector<T>::c_not_value_) {
78  break; // will set to failed
79  } else if (vec_->internal_array.is_descriptor(cvalue, spot)) {
80  continue;
81  } else {
82  assert(vec_->internal_array.is_valid(cvalue));
84  WriteHelper<T> >(this, cvalue);
85 
86  T help_t = reinterpret_cast<T>(util::memory::rc::mark_first(helper));
87  bool res = spot->compare_exchange_strong(cvalue, help_t);
88  if (res) {
89  WriteHelper<T> * helper_null = nullptr;
90  res = helper_.compare_exchange_strong(helper_null, helper);
91  res = (res || (helper_null == helper));
92  assert(helper_.load() != nullptr);
93 
94  T new_val;
95  if (res && (expected_ == cvalue)) {
96  new_val = new_val_;
97  } else {
98  new_val = cvalue;
99  }
100  spot->compare_exchange_strong(help_t, new_val);
101 
102  if (!res) {
104  }
105  return;
106 
107  } else {
108  util::memory::rc::free_descriptor(helper, true);
109  }
110  }
111  } // while value_ is c_not_value
112  }
113 
114 
115  WriteHelper<T> *helper_null = nullptr;
116  helper_.compare_exchange_strong(helper_null, c_fail_pointer_);
117  assert(helper_.load() != nullptr);
118  };
119 
120  bool result(T &expected) {
121  WriteHelper<T> * c_fail_pointer_ =
122  reinterpret_cast<WriteHelper<T> *>(~0x1L);
123  WriteHelper<T> * temp = helper_.load();
124  if (temp == c_fail_pointer_) {
125  return false; // out of bounds exception
126  } else if (temp->value() == expected_) {
127  return true;
128  } else {
129  expected = temp->value();
130  return false;
131  }
132  assert(false);
133  return false;
134  };
135 
136  bool is_watched() {
137  WriteHelper<T> * temp = helper_.load();
138 
139  if (temp == nullptr) {
140  assert(false); // THis state should not be reached
141  return false;
142  } else if (temp == reinterpret_cast<WriteHelper<T> *>(~0x1L)) {
143  return false;
144  } else {
145  return (helper_.load())->is_watched();
146  }
147  }
148 
149  private:
150  friend class WriteHelper<T>;
151  Vector<T> *vec_;
152  size_t idx_;
155  std::atomic<WriteHelper<T> *> helper_ {nullptr};
156 }; // class WriteOp
157 
158 template<typename T>
159 class WriteHelper: public tervel::util::Descriptor {
160  public:
161  explicit WriteHelper(WriteOp<T> *op, T val)
162  : op_(op)
163  , val_(val) {}
164 
165  T value() {
166  return val_;
167  }
168 
170  void * complete(void *value, std::atomic<void *> *address) {
171  void * marked = reinterpret_cast<void *>(
173  assert(marked == value);
174 
175  WriteHelper<T> * helper_null = nullptr;
176  bool res = op_->helper_.compare_exchange_strong(helper_null, this);
177  res = (res || (helper_null == this));
178  assert(op_->helper_.load() != nullptr);
179 
180  void *new_val;
181  if (res && (op_->expected_ == val_)) {
182  new_val = reinterpret_cast<void *>(op_->new_val_);
183  } else {
184  new_val = reinterpret_cast<void *>(val_);
185  }
186 
187  res = address->compare_exchange_strong(marked, new_val);
188  if (res) {
189  return new_val;
190  } else {
191  return marked;
192  }
193  }
194 
195  void * get_logical_value() {
196  WriteHelper<T> * helper = op_->helper_.load();
197  if (helper == this) {
198  return reinterpret_cast<void *>(op_->new_val_);
199  } else {
200  return reinterpret_cast<void *>(val_);
201  }
202  }
203 
216  bool on_watch(std::atomic<void *> *address, void * value) {
219  t_SlotID::SHORTUSE, op_, address, value);
220 
221  if (success) {
222  /* Success, means that the WriteOP referenced by this Helper can not
223  * be freed while we check to make sure this Helper is associated with
224  * it. */
225  WriteHelper<T> *helper = op_->helper_.load();
226  if (helper == nullptr) {
227  if (op_->helper_.compare_exchange_strong(helper, this)) {
228  /* If this passed then helper == nullptr, so we set it to be ==
229  * this */
230  helper = this;
231  }
232  }
233 
234  assert(op_->helper_.load() == helper);
235 
236  if (helper != this) {
237  /* This Helper was placed in error, remove it and replace it with the
238  * logic value of this object (expected_value)
239  */
240  address->compare_exchange_strong(value, reinterpret_cast<void *>(val_));
241  } else {
242  address->compare_exchange_strong(value, reinterpret_cast<void *>(op_->new_val_));
243  }
244  /* No longer need HP protection, if we have RC protection on an associated
245  * Helper. If we don't it, the value at this address must have changed and
246  * we don't need it either way.
247  */
248  util::memory::hp::HazardPointer::unwatch(t_SlotID::SHORTUSE);
249  } // End Successful watch
250 
251  return false;
252  };
253 
254  private:
255  friend class WriteOp<T>;
257  const T val_;
258 }; // class WriteHelper
259 } // namespace vector
260 } // namespace wf
261 } // namespace containers
262 } // namespace tervel
263 #endif // __TERVEL_CONTAINERS_WF_VECTOR_WRITE_OP_H
WriteOp(Vector< T > *vec, size_t idx, T expected, T val)
Definition: write_op.h:50
DescrType * get_descriptor(Args &&...args)
Constructs and returns a descriptor.
Definition: descriptor_util.h:50
__thread void * tl_control_word
WriteOp< T > * op_
Definition: write_op.h:256
WriteHelper(WriteOp< T > *op, T val)
Definition: write_op.h:161
void * complete(void *value, std::atomic< void * > *address)
This method is implemented by each sub class and must guarantee that upon return that the descriptor ...
Definition: write_op.h:170
void * mark_first(tervel::util::Descriptor *descr)
This returns the passed reference with its least signifcant bit set to 1.
Definition: descriptor_util.h:157
T new_val_
Definition: write_op.h:154
bool result(T &expected)
Definition: write_op.h:120
void free_descriptor(tervel::util::Descriptor *descr, bool dont_check=false)
Once a user is done with a descriptor, they should free it with this method.
Definition: descriptor_util.h:65
void help_complete()
Implementations of this function that upon its return the operation described in the OpRecord has bee...
Definition: write_op.h:66
TODO(steven):
Definition: mcas.h:36
const T val_
Definition: write_op.h:257
void * get_logical_value()
This method is implemented by each sub class.
Definition: write_op.h:195
This defines the Descriptor class, this class is designed to be extend and be used in conjunction wit...
Definition: descriptor.h:60
bool is_watched()
Definition: write_op.h:136
static void unwatch(SlotID slot_id, HazardPointer *const hazard_pointer=tervel::tl_thread_info->get_hazard_pointer())
This method is used to remove the hazard pointer watch.
static bool watch(SlotID slot_id, Element *elem, std::atomic< void * > *address, void *expected, HazardPointer *const hazard_pointer=tervel::tl_thread_info->get_hazard_pointer())
This method is used to achieve a hazard pointer watch on the the based descr.
virtual void * complete(void *current, std::atomic< void * > *address)=0
This method is implemented by each sub class and must guarantee that upon return that the descriptor ...
This class is used to create Operation Records.
Definition: progress_assurance.h:52
~WriteOp()
Definition: write_op.h:56
virtual bool on_watch(std::atomic< void * > *, void *)
This method is optional to implement for each sub class.
Definition: descriptor.h:99
Vector< T > * vec_
Definition: write_op.h:151
T value()
Definition: write_op.h:165
std::atomic< WriteHelper< T > * > helper_
Definition: write_op.h:155
bool on_watch(std::atomic< void * > *address, void *value)
This method is optional to implement for each sub class.
Definition: write_op.h:216
size_t idx_
Definition: write_op.h:152
T expected_
Definition: write_op.h:153
SlotID
Definition: hazard_pointer.h:58