00001
00027 #ifndef GALOIS_WORKLIST_STABLEITERATOR_H
00028 #define GALOIS_WORKLIST_STABLEITERATOR_H
00029
00030 #include "Galois/gstl.h"
00031
00032 namespace Galois {
00033 namespace WorkList {
00034
00035 template<typename Iterator=int*, bool Steal = false>
00036 struct StableIterator {
00037 typedef typename std::iterator_traits<Iterator>::value_type value_type;
00038
00040 template<bool _concurrent>
00041 struct rethread { typedef StableIterator<Iterator, Steal> type; };
00042
00044 template<typename _T>
00045 struct retype { typedef StableIterator<Iterator, Steal> type; };
00046
00047 template<typename _iterator>
00048 struct with_iterator { typedef StableIterator<_iterator, Steal> type; };
00049
00050 template<bool _steal>
00051 struct with_steal { typedef StableIterator<Iterator, _steal> type; };
00052
00053 private:
00054 struct shared_state {
00055 Iterator stealBegin;
00056 Iterator stealEnd;
00057 Runtime::LL::SimpleLock<true> stealLock;
00058 bool stealAvail;
00059 void resetAvail() {
00060 if (stealBegin != stealEnd)
00061 stealAvail = true;
00062 }
00063 };
00064
00065 struct state {
00066 Runtime::LL::CacheLineStorage<shared_state> stealState;
00067 Iterator localBegin;
00068 Iterator localEnd;
00069 unsigned int nextVictim;
00070
00071 void populateSteal() {
00072 if (Steal && localBegin != localEnd) {
00073 shared_state& s = stealState.data;
00074 s.stealLock.lock();
00075 s.stealEnd = localEnd;
00076 s.stealBegin = localEnd = Galois::split_range(localBegin, localEnd);
00077 s.resetAvail();
00078 s.stealLock.unlock();
00079 }
00080 }
00081 };
00082
00083 Runtime::PerThreadStorage<state> TLDS;
00084
00085 bool doSteal(state& dst, state& src, bool wait) {
00086 shared_state& s = src.stealState.data;
00087 if (s.stealAvail) {
00088 if (wait) {
00089 s.stealLock.lock();
00090 } else if (!s.stealLock.try_lock()) {
00091 return false;
00092 }
00093 if (s.stealBegin != s.stealEnd) {
00094 dst.localBegin = s.stealBegin;
00095 s.stealBegin = dst.localEnd = Galois::split_range(s.stealBegin, s.stealEnd);
00096 s.resetAvail();
00097 }
00098 s.stealLock.unlock();
00099 }
00100 return dst.localBegin != dst.localEnd;
00101 }
00102
00103
00104 Galois::optional<value_type> pop_steal(state& data) {
00105
00106 if (doSteal(data, data, true))
00107 return *data.localBegin++;
00108
00109 if (doSteal(data, *TLDS.getRemote(data.nextVictim), false)) {
00110
00111 if (data.nextVictim != Runtime::LL::getTID())
00112 data.populateSteal();
00113 return *data.localBegin++;
00114 }
00115 ++data.nextVictim;
00116 data.nextVictim %= Runtime::activeThreads;
00117 return Galois::optional<value_type>();
00118 }
00119
00120 public:
00123 template<typename RangeTy>
00124 void push_initial(const RangeTy& r) {
00125 state& data = *TLDS.getLocal();
00126 data.localBegin = r.local_begin();
00127 data.localEnd = r.local_end();
00128 data.nextVictim = Runtime::LL::getTID();
00129 data.populateSteal();
00130 }
00131
00133 Galois::optional<value_type> pop() {
00134 state& data = *TLDS.getLocal();
00135 if (data.localBegin != data.localEnd)
00136 return *data.localBegin++;
00137 if (Steal)
00138 return pop_steal(data);
00139 return Galois::optional<value_type>();
00140 }
00141
00142 void push(const value_type& val) {
00143 abort();
00144 }
00145
00146 template<typename Iter>
00147 void push(Iter b, Iter e) {
00148 abort();
00149 }
00150 };
00151 GALOIS_WLCOMPILECHECK(StableIterator)
00152
00153 }
00154 }
00155 #endif