00001 //---------------------------------------------------------------------------- 00002 /** @file LinkedList.hpp 00003 Lock-free sorted linked list. 00004 */ 00005 //---------------------------------------------------------------------------- 00006 00007 #ifndef LINKEDLIST_HPP 00008 #define LINKEDLIST_HPP 00009 00010 #include "Benzene.hpp" 00011 #include "SafeBool.hpp" 00012 #include <cassert> 00013 #include <iostream> 00014 #include <boost/utility.hpp> 00015 00016 _BEGIN_BENZENE_NAMESPACE_ 00017 00018 //---------------------------------------------------------------------------- 00019 00020 /** A node occuring in an instance of LinkedList. */ 00021 template<typename T> 00022 class ListNode 00023 { 00024 public: 00025 ListNode(); 00026 00027 ListNode(const T& data); 00028 00029 bool AddChild(ListNode<T>* child, ListNode<T>* successor) volatile; 00030 00031 void Delete() volatile; 00032 00033 private: 00034 T m_data; 00035 00036 bool m_locked; 00037 00038 bool m_deleted; 00039 00040 ListNode<T>* m_next; 00041 00042 ListNode<T>* m_dead; 00043 00044 struct ScopedLock 00045 { 00046 volatile ListNode<T>& m_obj; 00047 00048 ScopedLock(volatile ListNode<T>& obj) 00049 : m_obj(obj) 00050 { 00051 while (!__sync_bool_compare_and_swap(&m_obj.m_locked, false, true)) 00052 ; 00053 } 00054 ~ScopedLock() 00055 { 00056 m_obj.m_locked = false; 00057 } 00058 }; 00059 00060 ListNode<T>* GetNext() volatile; 00061 00062 void TryFixLink(ListNode<T>* node) volatile; 00063 00064 template<typename U> friend class Pool; 00065 00066 template<typename U> friend class ListIterator; 00067 00068 template<typename U> friend class LinkedList; 00069 }; 00070 00071 00072 template<typename T> 00073 ListNode<T>::ListNode() 00074 : m_locked(false), 00075 m_deleted(false), 00076 m_next(0), 00077 m_dead(0) 00078 { 00079 } 00080 00081 template<typename T> 00082 ListNode<T>::ListNode(const T& data) 00083 : m_data(data), 00084 m_locked(false), 00085 m_deleted(false), 00086 m_next(0), 00087 m_dead(0) 00088 { 00089 } 00090 00091 /** Locks the node and adds the given child. */ 00092 template<typename T> 00093 bool ListNode<T>::AddChild(ListNode<T>* child, ListNode<T>* successor) volatile 00094 { 00095 ScopedLock lock(*this); 00096 if (!m_deleted && m_next == successor) 00097 { 00098 child->m_next = m_next; 00099 m_next = child; 00100 return true; 00101 } 00102 return false; 00103 } 00104 00105 /** Logically deletes this node. 00106 Node must be locked while doing so to prevent the node from being 00107 deleted inside another thread's AddChild() call. */ 00108 template<typename T> 00109 void ListNode<T>::Delete() volatile 00110 { 00111 ScopedLock lock(*this); 00112 m_deleted = true; 00113 } 00114 00115 /** Attempts to physically delete a logically deleted node. */ 00116 template<typename T> 00117 void ListNode<T>::TryFixLink(ListNode<T>* node) volatile 00118 { 00119 ScopedLock lock(*this); 00120 if (m_next == node) 00121 m_next = node->m_next; 00122 } 00123 00124 /** Returns the next node in the list. 00125 Tries to physically delete any logically deleted nodes it 00126 encounters along the way. */ 00127 template<typename T> 00128 ListNode<T>* ListNode<T>::GetNext() volatile 00129 { 00130 ListNode<T>* node = m_next; 00131 while ((node != 0) && node->m_deleted) 00132 { 00133 TryFixLink(node); 00134 node = node->m_next; 00135 } 00136 return node; 00137 } 00138 00139 //---------------------------------------------------------------------------- 00140 00141 /** Pool of pre-allocated memory. 00142 Allocates more memory when current amount is used up. 00143 */ 00144 template<typename T> 00145 class Pool : boost::noncopyable 00146 { 00147 public: 00148 00149 static const std::size_t CHUNK_SIZE = 1 << 24; // 16MB 00150 00151 Pool(); 00152 00153 ~Pool(); 00154 00155 std::size_t Allocated() const; 00156 00157 std::size_t ChunkSize() const; 00158 00159 /** Grabs memory from pool in threadsafe manner. */ 00160 ListNode<T>* Get() volatile; 00161 00162 /** Adds a node to the list of dead nodes in a threadsafe manner. */ 00163 void AddToDeadList(ListNode<T>* node) volatile; 00164 00165 /** Puts node back on pool, not threadsafe. */ 00166 void Put(ListNode<T>* node); 00167 00168 /** Returns dead nodes to pool. */ 00169 void RaiseTheDead(); 00170 00171 private: 00172 ListNode<T>* m_head; 00173 00174 ListNode<T>* m_dead; 00175 00176 bool m_lockedHead; 00177 00178 bool m_lockedDead; 00179 00180 std::size_t m_allocated; 00181 00182 std::size_t m_chunkSize; 00183 00184 std::vector<ListNode<T>* > m_chunks; 00185 00186 void Allocate(); 00187 }; 00188 00189 template<typename T> 00190 Pool<T>::Pool() 00191 : m_head(0), 00192 m_dead(0), 00193 m_lockedHead(false), 00194 m_lockedDead(false), 00195 m_allocated(0), 00196 m_chunkSize(CHUNK_SIZE) 00197 { 00198 Allocate(); 00199 } 00200 00201 template<typename T> 00202 Pool<T>::~Pool() 00203 { 00204 for (std::size_t i = 0; i < m_chunks.size(); ++i) 00205 delete [] m_chunks[i]; 00206 } 00207 00208 template<typename T> 00209 std::size_t Pool<T>::Allocated() const 00210 { 00211 return m_allocated; 00212 } 00213 00214 template<typename T> 00215 std::size_t Pool<T>::ChunkSize() const 00216 { 00217 return m_chunkSize; 00218 } 00219 00220 template<typename T> 00221 void Pool<T>::Allocate() 00222 { 00223 assert(m_head == 0); 00224 std::size_t num = m_chunkSize / sizeof(ListNode<T>); 00225 ListNode<T>* data = new ListNode<T>[num]; 00226 m_chunks.push_back(data); 00227 for (std::size_t i = 0; i < num - 1; ++i) 00228 data[i].m_next = &data[i + 1]; 00229 data[num - 1].m_next = 0; 00230 m_head = data; 00231 m_allocated += num * sizeof(ListNode<T>); 00232 } 00233 00234 template<typename T> 00235 ListNode<T>* Pool<T>::Get() volatile 00236 { 00237 while (!__sync_bool_compare_and_swap(&m_lockedHead, false, true)); 00238 if (m_head == 0) 00239 { 00240 // Strip volatile-ness since we are locked 00241 Pool<T>& ref = const_cast<Pool<T>&>(*this); 00242 ref.Allocate(); 00243 } 00244 ListNode<T>* ret = m_head; 00245 m_head = m_head->m_next; 00246 m_lockedHead = false; 00247 return ret; 00248 } 00249 00250 template<typename T> 00251 void Pool<T>::AddToDeadList(ListNode<T>* node) volatile 00252 { 00253 while (!__sync_bool_compare_and_swap(&m_lockedDead, false, true)); 00254 node->m_dead = m_dead; 00255 m_dead = node; 00256 m_lockedDead = false; 00257 } 00258 00259 template<typename T> 00260 void Pool<T>::RaiseTheDead() 00261 { 00262 ListNode<T>* node = m_dead; 00263 while (node) 00264 { 00265 ListNode<T>* next = node->m_dead; 00266 node->m_dead = 0; 00267 Put(node); 00268 node = next; 00269 } 00270 m_dead = 0; 00271 } 00272 00273 template<typename T> 00274 void Pool<T>::Put(ListNode<T>* node) 00275 { 00276 node->m_next = m_head; 00277 m_head = node; 00278 } 00279 00280 //---------------------------------------------------------------------------- 00281 00282 /** Lock-free linked list. 00283 Uses memory from the supplied Pool object. 00284 */ 00285 template<typename T> 00286 class LinkedList 00287 { 00288 public: 00289 LinkedList(Pool<T>& pool); 00290 00291 LinkedList(const LinkedList<T>& other); 00292 00293 virtual ~LinkedList(); 00294 00295 bool Empty() const; 00296 00297 void Add(const T& data); 00298 00299 void Remove(const T& data); 00300 00301 void Clear(); 00302 00303 void operator=(const LinkedList<T>& other); 00304 00305 bool operator==(const LinkedList<T>& other) const; 00306 00307 private: 00308 template <typename U> friend class ListIterator; 00309 00310 Pool<T>& m_pool; 00311 00312 mutable ListNode<T> m_head; 00313 00314 void CopyList(const LinkedList<T>& other); 00315 }; 00316 00317 template<typename T> 00318 LinkedList<T>::LinkedList(Pool<T>& pool) 00319 : m_pool(pool) 00320 { 00321 m_head.m_next = 0; 00322 } 00323 00324 template<typename T> 00325 LinkedList<T>::LinkedList(const LinkedList<T>& other) 00326 : m_pool(other.m_pool) 00327 { 00328 CopyList(other); 00329 } 00330 00331 template<typename T> 00332 LinkedList<T>::~LinkedList() 00333 { 00334 } 00335 00336 template<typename T> 00337 bool LinkedList<T>::Empty() const 00338 { 00339 return m_head.GetNext() == 0; 00340 } 00341 00342 template<typename T> 00343 void LinkedList<T>::Clear() 00344 { 00345 ListNode<T>* node = m_head.GetNext(); 00346 while (node != 0) 00347 { 00348 ListNode<T>* next = node.GetNext(); 00349 m_pool.Put(node); 00350 node = next; 00351 } 00352 m_head.m_next = 0; 00353 } 00354 00355 template<typename T> 00356 void LinkedList<T>::CopyList(const LinkedList<T>& other) 00357 { 00358 assert(m_head.m_next == 0); 00359 ListNode<T>* them = other.m_head.GetNext(); 00360 ListNode<T>* mine = m_head; 00361 while (them != 0) 00362 { 00363 ListNode<T>* child = new (m_pool.Get()) ListNode<T>(them->m_data); 00364 mine->AddChild(child); 00365 mine = mine->GetNext(); 00366 them = them->GetNext(); 00367 } 00368 } 00369 00370 template<typename T> 00371 void LinkedList<T>::Add(const T& data) 00372 { 00373 ListNode<T>* node = 0; 00374 while (true) 00375 { 00376 ListNode<T>* current = &m_head; 00377 ListNode<T>* next = current->GetNext(); 00378 while ((next != 0) && next->m_data < data) 00379 { 00380 current = next; 00381 next = current->GetNext(); 00382 } 00383 // At this point: (next == 0 || next->m_data >= data) 00384 00385 // Check for duplicate 00386 if ((next != 0) && next->m_data == data) 00387 break; 00388 00389 // Try to add it in this location 00390 if (node == 0) 00391 node = new (m_pool.Get()) ListNode<T>(data); 00392 if (current->AddChild(node, next)) 00393 break; 00394 } 00395 } 00396 00397 template<typename T> 00398 void LinkedList<T>::Remove(const T& data) 00399 { 00400 ListNode<T>* parent = &m_head; 00401 ListNode<T>* next = parent->GetNext(); 00402 while ((next != 0) && next->m_data != data) 00403 { 00404 parent = next; 00405 next = parent->GetNext(); 00406 } 00407 if (next != 0) 00408 { 00409 next->Delete(); 00410 parent->TryFixLink(next); 00411 m_pool.AddToDeadList(next); 00412 } 00413 } 00414 00415 template<typename T> 00416 void LinkedList<T>::operator=(const LinkedList<T>& other) 00417 { 00418 Clear(); 00419 CopyList(other); 00420 } 00421 00422 template<typename T> 00423 bool LinkedList<T>::operator==(const LinkedList<T>& other) const 00424 { 00425 ListNode<T>* mine = m_head.GetNext(); 00426 ListNode<T>* them = other.m_head.GetNext(); 00427 while ((mine != 0) && (them != 0)) 00428 { 00429 if (mine->m_data != them->m_data) 00430 return false; 00431 mine = mine->GetNext(); 00432 them = them->GetNext(); 00433 } 00434 return (mine != 0) == (them != 0); 00435 } 00436 00437 //---------------------------------------------------------------------------- 00438 00439 /** Iterates over an instance of LinkedList. */ 00440 template<typename T> 00441 class ListIterator : public SafeBool<ListIterator<T> > 00442 { 00443 public: 00444 ListIterator(LinkedList<T>& lst); 00445 00446 T& operator*(); 00447 00448 ListIterator<T>& operator++(); 00449 00450 bool boolean_test() const; 00451 00452 private: 00453 ListNode<T>* m_current; 00454 00455 template <typename U> friend class LinkedList; 00456 }; 00457 00458 template<typename T> 00459 ListIterator<T>::ListIterator(LinkedList<T>& lst) 00460 : m_current(lst.m_head.GetNext()) 00461 { 00462 } 00463 00464 template<typename T> 00465 T& ListIterator<T>::operator*() 00466 { 00467 return m_current->m_data; 00468 } 00469 00470 template<typename T> 00471 ListIterator<T>& ListIterator<T>::operator++() 00472 { 00473 m_current = m_current->GetNext(); 00474 return *this; 00475 } 00476 00477 template<typename T> 00478 bool ListIterator<T>::boolean_test() const 00479 { 00480 return m_current != 0; 00481 } 00482 00483 //---------------------------------------------------------------------------- 00484 00485 _END_BENZENE_NAMESPACE_ 00486 00487 #endif // LINKEDLIST_HPP