Tervel  1.0.0
A collection of wait-free containers and algorithms.
shift_helper.h
Go to the documentation of this file.
1 #include "tervel/util/info.h"
5 
6 template<class ShiftOp, class T>
9 public:
10  const helper_t *prev_;
11  const ShiftOp *op_rec_;
12  const T replaced_value_;
13  std::atomic<helper_t *> next_{nullptr};
14 
15  ShiftHelper(ShiftOp * op_rec, helper_t *prev, T replaced_value )
16  : prev_(prev)
17  , op_rec(op_rec_)
18  , replaced_value_(replaced_value) {};
19 
20  bool complete_phase1(WFVector *vec, int pos);
21  bool complete(WFVector *vec, int pos);
22 
23 
24  using util::Descriptor::on_watch;
25  bool on_watch(std::atomic<void *> *address, void * value) {
26  typedef util::memory::hp::HazardPointer::SlotID t_SlotID;
28  t_SlotID::SHORTUSE, op_rec_, address, value);
29 
30  if (success && prev_ != nullptr) {
31  helper_t temp = prev->next_.load();
32  if (temp == nullptr) {
33  if (prev->next_.compare_exchange_strong(temp, this)) {
34  temp = this;
35  }
36  }
37 
38  if (temp != this) {
39  success = false;
40  address->compare_exchange_strong(value, replaced_value_);
41  }
42 
43  util::memory::hp::HazardPointer::unwatch(t_SlotID::SHORTUSE);
44  } // End Successfull watch
45 
46  if (success) {
47  assert(cas_row_->helper_.load() != nullptr);
48  assert(util::memory::rc::is_watched(this));
50  }
51 
52  return success;
53  };
54 
55 
56 
57  using util::Descriptor::get_logical_value;
58  void * get_logical_value() {
59  if (op_rec_->is_complete()) {
60  return next_.load()->replaced_value_;
61  } else {
62  return replaced_value_;
63  }
64  }
65 
66 }; // ShiftHelper
67 
68 
69 template<class ShiftType>
70 bool completeShift(ShiftType *op, WFVector *vec, int pos);
71 
72 
73 using util::Descriptor::complete;
74 void * helper_t::complete(void *value, std::atomic<void *> *address) {
75 
76 
77 
78 };
79 
80 
81 template<class ParentOp>
82 bool ShiftHelper<ParentOp>::complete_phase1(WFVector *vec, int pos){
83 
84  if(this->rvalue==NULL){
85  main->isComplete.store(true);
86  return true;
87  }
88  ShiftHelper<ParentOp> *lastHelper=this;
89  int i;
90 
91  for(i=pos+1; ; i++){
92  // if(i > vec->csize.load() *2 ){
93  // assert(false);...debugging, but could be hit in a non buggy case
94  // }
95  if (main->isComplete.load()){
96  return true;
97  }
98  else {
99  ArrayElement *spot=vec->getSpot(i);
100 
101 
102  while (true) {
103  void *current=spot->load();
104  ShiftHelper<ParentOp> *tempHelper=lastHelper->next.load();
105  if (tempHelper){
106 
107  lastHelper=tempHelper;
108 
109  if (lastHelper->rvalue == NOT_VALUE) {
110  main->isComplete.store(true);
111  return true;
112  }
113  else {
114  break;
115  }
116 
117  }
118  else if (Helper::isHelper(current)) {
119 
120 
121  Helper * tHelper= Helper::unmark(current);
122 
123  if(!tHelper->watch(current, spot)){
124  continue;
125  }
126 
127  if (tHelper->type == type) {
128  ShiftHelper<ParentOp> *tHelper2=( ShiftHelper<ParentOp> *)tHelper;
129  if(tHelper2->main==main){
130  ShiftHelper<ParentOp> *temp=NULL;
131  if (lastHelper->next.compare_exchange_strong(temp, tHelper2) || tHelper2 == temp){
132  lastHelper=tHelper2;
133 
134  if(tHelper2->rvalue == NOT_VALUE){
135  main->isComplete.store(true);
136  tHelper->unwatch();
137  return true;
138  }
139  }
140  else {
141  assert(main->isComplete.load()); //Next iteration the first if conditional must be true.
142  }
143 
144  tHelper->unwatch();
145  break;
146  }
147  }
148  else if(tHelper->type == dt_popBack) {
149  //This prevents a circular dependency between shift operations and tail operations.
150  PopHelper * tHelper2= (PopHelper *)(tHelper);
151  void *temp=NULL;
152  tHelper2->child.compare_exchange_strong(temp, (void *)0x1);
153  spot->compare_exchange_strong(current, NOT_VALUE);
154  tHelper->unwatch();
155  continue;
156 
157  }
158  else if(tHelper->type == dt_pushBack) {
159  //This prevents a circular dependency between shift operations and tail operations.
160  PushHelper * tHelper2= (PushHelper *)(tHelper);
161 
162  long tpos=tHelper2->pos.load();
163  if(tpos == -1){
164  if(tHelper2->pos.compare_exchange_strong(tpos, i)){
165  tpos=i;
166  }
167  }
168  tHelper2->complete(vec, i);
169 
170  tHelper->unwatch();
171  continue;
172 
173  }
174 
175  else if(tHelper->type >= dt_unknown) {
176  assert(false);
177  }
178 
179 
180  bool helpRes=Helper::remove(vec, i, current);
181  if(!helpRes && rDepth>0){
182  tHelper->unwatch();
183  return false;
184  }
185 
186  tHelper->unwatch();
187  continue;
188 
189  }
190  else {
191  ShiftHelper<ParentOp>* helper=new ShiftHelper<ParentOp>(main, lastHelper, current);
192  if (spot->compare_exchange_strong(current, Helper::mark(helper))){
193 
194  ShiftHelper<ParentOp> *temp=NULL;
195  if (lastHelper->next.compare_exchange_strong(temp, helper) || helper == temp){
196  lastHelper=helper;
197 
198  if(current == NOT_VALUE){
199  main->isComplete.store(true);
200  return true;
201  }
202  break;
203  }
204  else {
205  void *temp2=Helper::mark(helper);
206  spot->compare_exchange_strong(temp2, current);
207  helper->safeFree(); //was globally visable
208  assert(main->isComplete.load()); //Next iteration the first if conditional must be true.
209  return true;
210  }
211 
212  }
213  else {
214  //The valu at the address changed, and so did the value of current. So re-evaluate current...
215  helper->unsafeFree();//Was never globally visable
216  }
217 
218  }//End Else it is a valid position
219 
220  }//End While true loop
221 
222  }//End Else it is not compelte
223 
224  }//End For Loop.
225 
226  assert(false);
227  return false;
228 }//End Complete Phase 1
229 
230 
231 template<>
232 bool ShiftHelper<InsertAt>::complete(WFVector *vec, int pos){
233  ArrayElement *spot=vec->getSpot(pos);
234  void *current=Helper::mark(this);
235 
236  ShiftHelper<InsertAt> *temp=NULL;
237  if(parent == NULL){
238  if(main->next.compare_exchange_strong(temp, this) || temp==this){
239  if(!complete_phase1(vec, pos)){
240  assert(rDepth > 0 || main->isComplete.load());
241  return false;
242  }
243  assert(main->isComplete.load());
244  spot->compare_exchange_strong(current, main->rvalue);
245 
246  }
247  else{
248  assert(main->isComplete.load() || temp ==(ShiftHelper<InsertAt> *)0x1);
249  spot->compare_exchange_strong(current, rvalue);
250 
251  }
252 
253  }
254  else{
255  if(parent->next.compare_exchange_strong(temp, this) || temp==this){
256  if(!complete_phase1(vec, pos)){
257  assert(rDepth > 0 || main->isComplete.load());
258  return false;
259  }
260  assert(main->isComplete.load());
261  spot->compare_exchange_strong(current, parent->rvalue);
262 
263  }
264  else{
265  assert(main->isComplete.load() || temp ==(ShiftHelper<InsertAt> *)0x1);
266  spot->compare_exchange_strong(current, rvalue);
267 
268  }
269  }
270  return true;
271 }
272 
273 template<>
274 bool ShiftHelper<EraseAt>::complete(WFVector *vec, int pos){
275  ArrayElement *spot=vec->getSpot(pos);
276  void *current=Helper::mark(this);
277 
278  ShiftHelper<EraseAt> *temp=NULL;
279 
280  bool success;
281 
282  if (parent == NULL) {
283  success=main->next.compare_exchange_strong(temp, this) || temp==this;
284  }
285  else {
286  success=parent->next.compare_exchange_strong(temp, this) || temp==this;
287  }
288 
289  if (success) {
290  if(!complete_phase1(vec, pos)){
291  assert(rDepth > 0 || main->isComplete.load());
292  return false;
293  }
294 
295  assert(main->isComplete.load());
296 
297  if(next.load() == NULL){
298  spot->compare_exchange_strong(current, NOT_VALUE);
299  }
300  else{
301  spot->compare_exchange_strong(current, next.load()->rvalue);
302  }
303 
304  }
305  else {
306  assert(main->isComplete.load() || temp ==(ShiftHelper<EraseAt> *)0x1);
307  spot->compare_exchange_strong(current, rvalue);
308  }
309 
310  return true;
311 }
312 
313 
314 
315 template<class ShiftType>
316 bool completeShift(ShiftType *op, WFVector *vec, int pos){
317  if(pos >= vec->csize){
318  ShiftHelper<ShiftType> *temp=NULL;
319  if(op->next.compare_exchange_strong(temp, (ShiftHelper<ShiftType> *)(0x1))){
320  op->isComplete.store(true);
321  return true;
322  }
323 
324  }
325 
326 
327  while (true) {
328  if(fcount++==MAX_FAILURES){
329  if(rDepth == 0){
330  vec->announceOp(op);
331  }
332  else{
333  assert(false);
334  return false;
335  }
336  }
337 
338 
339  ShiftHelper<ShiftType> *temp=op->next.load();
340  if (temp == (ShiftHelper<ShiftType> *)0x1) {
341  op->isComplete.store(true);
342  return true;
343  }
344  else if (temp != NULL) {
345  temp->complete(vec,pos);
346  return true;
347  }
348 
349  ArrayElement *spot=vec->getSpot(pos);
350  void *current=spot->load();
351  if (Helper::isHelper(current)) {
352 
353  Helper * tHelper= Helper::unmark(current);
354  if(!tHelper->watch(current, spot)){
355  continue;
356  }
357 
358  if (tHelper->type == dt_shifthelper) {
359  ShiftHelper<ShiftType> *tHelper2=( ShiftHelper<ShiftType> *)tHelper;
360  if(tHelper2->main==op){
361  ShiftHelper<ShiftType> * temp=NULL;
362  if (op->next.compare_exchange_strong(temp, tHelper2) || tHelper2 == temp){
363 
364  if(tHelper2->rvalue == NOT_VALUE){
365  //main->isComplete.store(true);
366  assert(false);
367  op->isComplete.store(true);
368  tHelper->unwatch();
369  return true;;
370  }
371  else{
372  tHelper2->complete(vec,pos);
373  }
374  }
375 
376  assert(op->next.load());
377  if (temp == (ShiftHelper<ShiftType> *)0x1) {
378  op->isComplete.store(true);
379 
380  }
381  tHelper->unwatch();
382  return true;
383  }//End helper for this op
384  }//End If it is a insertAt descripor
385  /* No need since we have not placed anything yet
386  else if(tHelper->type == dt_popBack) {
387  //This prevents a circular dependency between shift operations and tail operations.
388  PopHelper * tHelper2= (PopHelper *)(tHelper);
389  void *temp=NULL;
390  tHelper2->child.compare_exchange_strong(temp, (void *)0x1);
391  spot->compare_exchange_strong(current, NOT_VALUE);
392  continue;
393 
394  }*/
395  else if(tHelper->type >= dt_unknown) {
396  assert(false);
397  op->isComplete.store(true);
398  tHelper->unwatch();
399  return false;;
400  }
401  Helper::remove(vec, pos, current);
402  tHelper->unwatch();
403 
404  continue;
405 
406  }
407  else if (current == NOT_VALUE) {
408  //temp=NULL; already null
409  if (op->next.compare_exchange_strong(temp, (ShiftHelper<ShiftType> *)(0x1)) || temp == (ShiftHelper<ShiftType> *)0x1) {
410  op->isComplete.store(true);
411  return true;
412  }
413  else {
414  temp->complete(vec, pos);
415  return true;
416  }
417  }
418  else {
419  ShiftHelper<ShiftType>* helper=new ShiftHelper<ShiftType>(op, NULL, current);
420  if (spot->compare_exchange_strong(current, Helper::mark(helper))) {
421  helper->complete(vec,pos);
422  if (op->next.load() != helper) {
423  helper->safeFree(); //was not associated because op was already done when it was placed.
424  }
425  return true;
426  }
427  else {
428  //The value at the address changed, So re-evaluate current (which changes on a failed compare and exchange)...
429  helper->unsafeFree();//Was never globally visable.
430  }
431  }//End Else it is a valid value
432  }//End While true loop
433 
434  assert(false);
435 };//End begin complete
ShiftHelper(ShiftOp *op_rec, helper_t *prev, T replaced_value)
Definition: shift_helper.h:15
const T replaced_value_
Definition: shift_helper.h:12
Definition: shift_helper.h:7
Definition: push_helper.h:2
std::atomic< void * > child
Definition: pop_helper.h:5
bool on_watch(std::atomic< void * > *address, void *value)
This method is optional to implement for each sub class.
Definition: shift_helper.h:25
const helper_t * prev_
Definition: shift_helper.h:10
void unwatch(tervel::util::Descriptor *descr)
This method is used to decrement the reference count of the passed descriptor object.
Definition: descriptor_util.h:139
ShiftHelper< ShiftOp, T > helper_t
Definition: shift_helper.h:8
bool completeShift(ShiftType *op, WFVector *vec, int pos)
Definition: shift_helper.h:316
bool complete(WFVector *vec, int pos)
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
bool complete(WFVector *vec, int pos)
Definition: push_helper.h:73
void * get_logical_value()
This method is implemented by each sub class.
Definition: shift_helper.h:58
This defines the Descriptor class, this class is designed to be extend and be used in conjunction wit...
Definition: descriptor.h:60
std::atomic< helper_t * > next_
Definition: shift_helper.h:13
bool watch(tervel::util::Descriptor *descr, std::atomic< void * > *address, void *value)
This method is used to increment the reference count of the passed descriptor object.
Definition: descriptor_util.h:105
const ShiftOp * op_rec_
Definition: shift_helper.h:11
Definition: pop_helper.h:3
std::atomic< long > pos
Definition: push_helper.h:5
bool complete_phase1(WFVector *vec, int pos)
Definition: shift_helper.h:82