Tervel  1.0.0
A collection of wait-free containers and algorithms.
descriptor_util.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_MEMORY_RC_UTIL_DESCRIPTOR_H_
26 #define TERVEL_MEMORY_RC_UTIL_DESCRIPTOR_H_
27 
28 #include <tervel/util/info.h>
29 #include <tervel/util/descriptor.h>
35 
36 namespace tervel {
37 namespace util {
38 
39 class Descriptor;
40 
41 namespace memory {
42 namespace rc {
43 
49 template<typename DescrType, typename... Args>
50 inline DescrType * get_descriptor(Args&&... args) {
51  auto rc_descr_pool = tervel::tl_thread_info->get_rc_descriptor_pool();
52  return rc_descr_pool->get_descriptor<DescrType>(std::forward<Args>(args)...);
53 }
54 
66  bool dont_check = false) {
68  dont_check);
69 }
70 
78 inline bool is_watched(tervel::util::Descriptor *descr) {
79  #ifdef TERVEL_MEM_RC_NO_WATCH
80  return false;
81  #endif // TERVEL_MEM_RC_NO_WATCH
82  PoolElement * elem = get_elem_from_descriptor(descr);
83  int64_t ref_count = elem->header().ref_count.load();
84  assert(ref_count >=0 && " Ref count of an object is negative, which implies some thread called unwatch multiple times on the same object");
85  if (ref_count == 0) {
86  return descr->on_is_watched();
87  } else {
88  return true;
89  }
90 }
91 
105 inline bool watch(tervel::util::Descriptor *descr, std::atomic<void *> *address,
106  void *value) {
107  #ifdef TERVEL_MEM_RC_NO_WATCH
108  return true;
109  #endif // TERVEL_MEM_RC_NO_WATCH
110 
111  PoolElement *elem = get_elem_from_descriptor(descr);
112  elem->header().ref_count.fetch_add(1);
113 
114  if (address->load() != value) {
115  int64_t temp = elem->header().ref_count.fetch_add(-1);
116  assert(temp > 0 && " Ref count of an object is negative, which implies some thread called unwatch multiple times on the same object");
117  return false;
118  } else {
119  bool res = descr->on_watch(address, value);
120  if (res) {
121  assert(is_watched(descr) && "On watch returned true, but the object is not watched. Error could exist on either [on_]watch or [on_]is_watched functions");
122  return true;
123  } else {
124  int64_t temp = elem->header().ref_count.fetch_add(-1);
125  assert(temp > 0 && " Ref count of an object is negative, which implies some thread called unwatch multiple times on the same object");
126  return false;
127  }
128  }
129 }
130 
139 inline void unwatch(tervel::util::Descriptor *descr) {
140  #ifdef TERVEL_MEM_RC_NO_WATCH
141  return;
142  #endif // TERVEL_MEM_RC_NO_WATCH
143 
144  PoolElement *elem = get_elem_from_descriptor(descr);
145  int64_t temp = elem->header().ref_count.fetch_add(-1);
146  assert(temp > 0 && " Ref count of an object is negative, which implies some thread called unwatch multiple times on the same object");
147  descr->on_unwatch();
148 }
149 
157 inline void * mark_first(tervel::util::Descriptor *descr) {
158  return reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(descr) | 0x1L);
159 }
160 
167 inline void atomic_mark_first(std::atomic<void*> *address) {
168  std::atomic<uintptr_t> *temp = reinterpret_cast<std::atomic<uintptr_t> *>(address);
169  temp->fetch_or(0x1);
170 }
171 
178 inline tervel::util::Descriptor * unmark_first(void *descr) {
179  return reinterpret_cast<tervel::util::Descriptor *>(
180  reinterpret_cast<uintptr_t>(descr) & ~0x1L);
181 }
182 
189 inline bool is_descriptor_first(void *descr) {
190  return (0x1L == (reinterpret_cast<uintptr_t>(descr) & 0x1L));
191 }
192 
208 inline void * remove_descriptor(void *expected, std::atomic<void *> *address) {
210  void *newValue;
212  newValue = nullptr; // result not used
213  } else {
214  tervel::util::Descriptor *descr = unmark_first(expected);
215  if (watch(descr, address, expected)) {
216  newValue = descr->complete(expected, address);
217  unwatch(descr);
218  } else {
219  newValue = address->load();
220  }
221  }
222  return newValue;
223 }
224 
233 inline void *descriptor_read_first(std::atomic<void *> *address) {
234  void *current_value = address->load();
235 
237 
238 
239  while (is_descriptor_first(current_value)) {
240 
241  if (progAssur.isDelayed()) {
242  ReadFirstOp *op = new ReadFirstOp(address);
244  reinterpret_cast<tervel::util::OpRecord *>(op));
245  current_value = op->load();
246  op->safe_delete();
247  return current_value;
248  } else {
249  tervel::util::Descriptor *descr = unmark_first(current_value);
250  if (watch(descr, address, current_value)) {
251  current_value = descr->get_logical_value();
252  unwatch(descr);
253  } else {
254  current_value = address->load();
255  }
256  }
257  }
258  return current_value;
259 }
260 
261 } // namespace rc
262 } // namespace memory
263 } // namespace util
264 } // namespace tervel
265 
266 
267 #endif // TERVEL_MEMORY_RC_UTIL_DESCRIPTOR_H_
DescrType * get_descriptor(Args &&...args)
Constructs and returns a descriptor.
Definition: descriptor_util.h:50
virtual void * get_logical_value()=0
This method is implemented by each sub class.
virtual void on_unwatch()
This method must be implemented if on_watch is implemented, and is optional otherwise.
Definition: descriptor.h:109
PoolElement * get_elem_from_descriptor(tervel::util::Descriptor *descr)
If the given descriptor was allocated through a DescriptorPool, then it has an associated PoolElement...
Definition: pool_element.h:166
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
util::memory::rc::DescriptorPool *const get_rc_descriptor_pool()
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 atomic_mark_first(std::atomic< void * > *address)
This function atomically bit marks the value at address.
Definition: descriptor_util.h:167
TODO(steven):
Definition: mcas.h:36
Helper class for RAII management of recursive helping of threads.
Definition: recursive_action.h:38
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
Header & header()
A reference to the header which houses all the special info.
Definition: pool_element.h:90
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.
virtual bool on_is_watched()
This method is optional to implement for each sub class.
Definition: descriptor.h:117
static void make_announcement(OpRecord *op, const uint64_t tid=tervel::tl_thread_info->get_thread_id(), ProgressAssurance *const prog_assur=tervel::tl_thread_info->get_progress_assurance())
This function places the.
Definition: progress_assurance.h:172
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
__thread ThreadContext * tl_thread_info
tervel::util::Descriptor * unmark_first(void *descr)
This returns an unbitmarked reference.
Definition: descriptor_util.h:178
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 ...
void safe_delete(bool no_check=false, ElementList *const element_list=tervel::tl_thread_info->get_hp_element_list())
This function is used to free a hazard pointer protected object if it is safe to do so OR add it to a...
Definition: hp_element.h:67
void * descriptor_read_first(std::atomic< void * > *address)
This function determines the logical value of an address which may have either a RC descriptor or a n...
Definition: descriptor_util.h:233
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
bool is_descriptor_first(void *descr)
This returns whether or not the least significant bit holds a bitmark.
Definition: descriptor_util.h:189
This class is used to hold the memory management information (Header) and a descriptor object...
Definition: pool_element.h:46
DescrType * get_descriptor(Args &&...args)
Constructs and returns a descriptor.
Definition: descriptor_pool.h:212
virtual bool on_watch(std::atomic< void * > *, void *)
This method is optional to implement for each sub class.
Definition: descriptor.h:99
std::atomic< int64_t > ref_count
Definition: pool_element.h:54
void * remove_descriptor(void *expected, std::atomic< void * > *address)
This method is used to remove a descriptor object that is conflict with another threads operation...
Definition: descriptor_util.h:208
bool isDelayed(size_t val=1)
Definition: progress_assurance.h:125
Definition: progress_assurance.h:120
Class used for placement in the Op Table to complete an operation that failed to complete in a bounde...
Definition: descriptor_read_first_op.h:44