Tervel  1.0.0
A collection of wait-free containers and algorithms.
mcas_helper.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_MCAS_MCAS_HELPER_H_
26 #define TERVEL_MCAS_MCAS_HELPER_H_
27 
28 #include <tervel/util/info.h>
29 #include <tervel/util/descriptor.h>
32 
35 
36 namespace tervel {
37 namespace algorithms {
38 namespace wf {
39 namespace mcas {
40 
41 template<class T>
42 class MCAS;
43 template<class T>
44 class CasRow;
45 
46 template<class T>
51 class Helper : public util::Descriptor {
52  public:
60  Helper<T>(MCAS<T> *mcas_op, CasRow<T> *cas_row)
61  : cas_row_(cas_row), mcas_op_(mcas_op) {}
62 
74  bool on_watch(std::atomic<void *> *address, void * value) {
77  t_SlotID::SHORTUSE, mcas_op_, address, value);
78 
79  if (success) {
80  /* Success, means that the MCAS object referenced by this Helper can not
81  * be freed while we check to make sure this Helper is assocaited with
82  * it. */
83  Helper<T> *curr_mch = cas_row_->helper_.load();
84  if (curr_mch == nullptr) {
85  if (cas_row_->helper_.compare_exchange_strong(curr_mch, this)) {
86  /* If this passed then curr_mch == nullptr, so we set it to be ==
87  * this */
88  curr_mch = this;
89  }
90  }
91 
92  assert(cas_row_->helper_.load() == curr_mch);
93 
94  if (curr_mch != this) {
95  /* This Helper was placed in error, remove it and replace it with the
96  * logic value of this object (expected_value)
97  */
98  address->compare_exchange_strong(value, cas_row_->expected_value_);
99  success = false;
100  }
101  /* No longer need HP protection, if we have RC protection on an associated
102  * Helper. If we don't it, the value at this address must have changed and
103  * we don't need it either way.
104  */
105  util::memory::hp::HazardPointer::unwatch(t_SlotID::SHORTUSE);
106  } // End Successfull watch
107 
108  if (success) {
109  assert(cas_row_->helper_.load() != nullptr);
110  assert(util::memory::rc::is_watched(this));
112  }
113 
114  return success;
115  };
116 
117 
127  void * complete(void *value, std::atomic<void *> *address) {
128  assert(cas_row_->helper_.load());
129  assert(util::memory::rc::is_watched(this));
131  Helper<T>* temp_null = nullptr;
132  this->cas_row_->helper_.compare_exchange_strong(temp_null, this);
133 
134  bool success = false;
135  if (temp_null == nullptr || temp_null == this) {
136  /* This implies it was successfully associated
137  So call the complete function of the MCAS operation */
138  success = this->mcas_op_->mcas_complete(this->cas_row_);
140  /* If the thread is performing a recursive return back to its own
141  operation, then just return null, it will be ignored. */
142  return nullptr;
143  }
144  }
145 
146  if (success) {
147  /* If the MCAS op was successfull then remove the Helper by replacing
148  it with the new_value */
149  address->compare_exchange_strong(value,
150  reinterpret_cast<void *>(this->cas_row_->new_value_));
151  } else {
152  /*Otherwise remove the Helper by replacing it with the expected_value*/
153  address->compare_exchange_strong(value,
154  reinterpret_cast<void *>(this->cas_row_->expected_value_));
155  }
156  // Return the new current value of the position
157  return address->load();
158  };
159 
168  void * get_logical_value() {
169  if (this->mcas_op_->state_ == MCAS<T>::MCasState::PASS) {
170  return this->cas_row_->new_value_;
171  }
172 
173  return this->cas_row_->expected_value_;
174  }
175 
176  private:
177  // The Row in the MCAS operation this MCH was placed for
179  // The MCAS which contains the cas_row_
181 }; // Helper
182 
183 
184 
185 } // namespace mcas
186 } // namespace wf
187 } // namespace algorithms
188 } // namespace tervel
189 
190 #endif // TERVEL_MCAS_MCAS_HELPER_H_
virtual void * get_logical_value()=0
This method is implemented by each sub class.
static bool is_watched(Element *descr, HazardPointer *const hazard_pointer=tervel::tl_thread_info->get_hazard_pointer())
This method is used to determine if a hazard pointer watch exists on a passed value.
This class is used to represent a one of the M CAS operations performed by an MCAS operation...
Definition: mcas_casrow.h:45
TODO(steven):
Definition: mcas.h:36
MCAS< T > * mcas_op_
Definition: mcas_helper.h:180
CasRow< T > * cas_row_
Definition: mcas_helper.h:178
bool on_watch(std::atomic< void * > *address, void *value)
This method is optional to implement for each sub class.
Definition: mcas_helper.h:74
bool is_watched(tervel::util::Descriptor *descr)
This method is used to determine if the passed descriptor is under rc protection. ...
Definition: descriptor_util.h:78
static bool recursive_return(bool change=false, bool value=false)
This defines the Descriptor class, this class is designed to be extend and be used in conjunction wit...
Definition: descriptor.h:60
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 ...
Definition: mcas_helper.h:42
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: mcas_helper.h:127
virtual bool on_watch(std::atomic< void * > *, void *)
This method is optional to implement for each sub class.
Definition: descriptor.h:99
void * get_logical_value()
This method is implemented by each sub class.
Definition: mcas_helper.h:168
This class is the MCAS operation's helper.
Definition: mcas_casrow.h:37
SlotID
Definition: hazard_pointer.h:58