00001 // simple galois context and contention manager -*- C++ -*- 00002 /* 00003 Galois, a framework to exploit amorphous data-parallelism in irregular 00004 programs. 00005 00006 Copyright (C) 2011, The University of Texas at Austin. All rights reserved. 00007 UNIVERSITY EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES CONCERNING THIS SOFTWARE 00008 AND DOCUMENTATION, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR ANY 00009 PARTICULAR PURPOSE, NON-INFRINGEMENT AND WARRANTIES OF PERFORMANCE, AND ANY 00010 WARRANTY THAT MIGHT OTHERWISE ARISE FROM COURSE OF DEALING OR USAGE OF TRADE. 00011 NO WARRANTY IS EITHER EXPRESS OR IMPLIED WITH RESPECT TO THE USE OF THE 00012 SOFTWARE OR DOCUMENTATION. Under no circumstances shall University be liable 00013 for incidental, special, indirect, direct or consequential damages or loss of 00014 profits, interruption of business, or related expenses which may arise from use 00015 of Software or Documentation, including but not limited to those resulting from 00016 defects in Software and/or Documentation, or loss or inaccuracy of data of any 00017 kind. 00018 */ 00019 00020 #ifndef _GALOIS_RUNTIME_CONTEXT_H 00021 #define _GALOIS_RUNTIME_CONTEXT_H 00022 00023 #include <boost/intrusive/slist.hpp> 00024 00025 #include "Galois/Runtime/SimpleLock.h" 00026 #include "Galois/ConflictFlags.h" 00027 00028 namespace GaloisRuntime { 00029 00030 //All objects that may be locked (nodes primarily) must inherit from Lockable 00031 //Use an intrusive list to track objects in a context without allocation overhead 00032 class LockableListTag; 00033 typedef boost::intrusive::slist_base_hook<boost::intrusive::tag<LockableListTag>,boost::intrusive::link_mode<boost::intrusive::normal_link> > LockableBaseHook; 00034 00035 class Lockable : public LockableBaseHook, public PtrLock<void*, true> { 00036 }; 00037 00038 class SimpleRuntimeContext { 00039 00040 typedef boost::intrusive::slist<Lockable, boost::intrusive::base_hook<LockableBaseHook>, boost::intrusive::constant_time_size<false>, boost::intrusive::linear<true> > locksTy; 00041 00042 //The locks we hold 00043 locksTy locks; 00044 00045 public: 00046 void start_iteration() { 00047 assert(locks.empty()); 00048 } 00049 00050 void cancel_iteration() { 00051 //FIXME: not handled yet 00052 commit_iteration(); 00053 } 00054 00055 void commit_iteration() { 00056 //Although the destructor for the list would do the unlink, 00057 //we do it here since we already are iterating 00058 while (!locks.empty()) { 00059 //ORDER MATTERS! 00060 Lockable& L = locks.front(); 00061 locks.pop_front(); 00062 L.unlock_and_clear(); 00063 } 00064 } 00065 00066 void acquire(Lockable* L) { 00067 bool suc = L->try_lock(); 00068 if (suc) { 00069 L->setValue(this); 00070 locks.push_front(*L); 00071 } else { 00072 if (L->getValue() != this) 00073 throw -1; //CONFLICT 00074 } 00075 } 00076 00077 }; 00078 00079 extern __thread SimpleRuntimeContext* thread_cnx; 00080 00082 static SimpleRuntimeContext* getThreadContext() { 00083 return thread_cnx; 00084 } 00085 00087 void setThreadContext(SimpleRuntimeContext* n); 00088 00089 00091 static inline bool shouldLock(Galois::MethodFlag g) { 00092 switch(g) { 00093 case Galois::NONE: 00094 case Galois::SAVE_UNDO: 00095 return false; 00096 case Galois::ALL: 00097 case Galois::CHECK_CONFLICT: 00098 return true; 00099 } 00100 assert(0 && "Shouldn't get here"); 00101 abort(); 00102 } 00103 00105 static __attribute__((unused)) void acquire(Lockable* C, Galois::MethodFlag m) { 00106 if (shouldLock(m)) { 00107 SimpleRuntimeContext* cnx = getThreadContext(); 00108 if (cnx) 00109 cnx->acquire(C); 00110 } 00111 } 00112 00113 } 00114 00115 #endif