00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef __WORKLISTEXPERIMENTAL_H_
00021 #define __WORKLISTEXPERIMENTAL_H_
00022
00023 namespace GaloisRuntime {
00024 namespace WorkList {
00025 namespace Experimental {
00026
00027 template<class T, typename ContainerTy = FIFO<T> >
00028 class StealingLocalWL : private boost::noncopyable {
00029
00030 PerCPU<ContainerTy> data;
00031
00032
00033
00034
00035
00036
00037 public:
00038 template<bool newconcurrent>
00039 struct rethread {
00040 typedef StealingLocalWL<T, ContainerTy> WL;
00041 };
00042
00043 typedef T value_type;
00044
00045 StealingLocalWL() {}
00046
00047 bool push(value_type val) {
00048 return data.get().push(val);
00049 }
00050
00051 std::pair<bool, value_type> pop() {
00052 std::pair<bool, value_type> ret = data.get().pop();
00053 if (ret.first)
00054 return ret;
00055 return data.getNext().pop();
00056 }
00057
00058 bool empty() {
00059 return data.get().empty();
00060 }
00061 bool aborted(value_type val) {
00062 return push(val);
00063 }
00064
00065
00066 template<typename Iter>
00067 void fill_initial(Iter ii, Iter ee) {
00068 while (ii != ee) {
00069 push(*ii++);
00070 }
00071 }
00072 };
00073 WLCOMPILECHECK(StealingLocalWL);
00074
00075 template<class T, class Indexer = DummyIndexer<T>, typename ContainerTy = FIFO<T>, bool concurrent=true >
00076 class ApproxOrderByIntegerMetric : private boost::noncopyable {
00077
00078 typename ContainerTy::template rethread<concurrent>::WL data[2048];
00079
00080 Indexer I;
00081 PerCPU<unsigned int> cursor;
00082
00083 int num() {
00084 return 2048;
00085 }
00086
00087 public:
00088
00089 typedef T value_type;
00090 template<bool newconcurrent>
00091 struct rethread {
00092 typedef ApproxOrderByIntegerMetric<T, Indexer, ContainerTy, newconcurrent> WL;
00093 };
00094
00095 ApproxOrderByIntegerMetric(const Indexer& x = Indexer())
00096 :I(x)
00097 {
00098 for (int i = 0; i < cursor.size(); ++i)
00099 cursor.get(i) = 0;
00100 }
00101
00102 bool push(value_type val) OPTNOINLINE {
00103 unsigned int index = I(val);
00104 index %= num();
00105 assert(index < num());
00106 return data[index].push(val);
00107 }
00108
00109 std::pair<bool, value_type> pop() OPTNOINLINE {
00110
00111 unsigned int& cur = concurrent ? cursor.get() : cursor.get(0);
00112 std::pair<bool, value_type> ret = data[cur].pop();
00113 if (ret.first)
00114 return ret;
00115
00116
00117 for (int i = 0; i <= num(); ++i) {
00118 cur = (cur + 1) % num();
00119 ret = data[cur].pop();
00120 if (ret.first)
00121 return ret;
00122 }
00123 return std::pair<bool, value_type>(false, value_type());
00124 }
00125
00126 bool empty() OPTNOINLINE {
00127 for (unsigned int i = 0; i < num(); ++i)
00128 if (!data[i].empty())
00129 return false;
00130 return true;
00131 }
00132
00133 bool aborted(value_type val) {
00134 return push(val);
00135 }
00136
00137
00138
00139 template<typename Iter>
00140 void fill_initial(Iter ii, Iter ee) {
00141 while (ii != ee) {
00142 push(*ii++);
00143 }
00144 }
00145 };
00146 WLCOMPILECHECK(ApproxOrderByIntegerMetric);
00147
00148 template<class T, class Indexer = DummyIndexer<T>, typename ContainerTy = FIFO<T>, bool concurrent=true >
00149 class LogOrderByIntegerMetric : private boost::noncopyable {
00150
00151 typename ContainerTy::template rethread<concurrent>::WL data[sizeof(unsigned int)*8 + 1];
00152
00153 Indexer I;
00154 PerCPU<unsigned int> cursor;
00155
00156 int num() {
00157 return sizeof(unsigned int)*8 + 1;
00158 }
00159
00160 int getBin(unsigned int i) {
00161 if (i == 0) return 0;
00162 return sizeof(unsigned int)*8 - __builtin_clz(i);
00163 }
00164
00165 public:
00166
00167 typedef T value_type;
00168 template<bool newconcurrent>
00169 struct rethread {
00170 typedef LogOrderByIntegerMetric<T, Indexer, ContainerTy, newconcurrent> WL;
00171 };
00172
00173 LogOrderByIntegerMetric(const Indexer& x = Indexer())
00174 :I(x)
00175 {
00176 for (int i = 0; i < cursor.size(); ++i)
00177 cursor.get(i) = 0;
00178 }
00179
00180 bool push(value_type val) {
00181 unsigned int index = I(val);
00182 index = getBin(index);
00183 return data[index].push(val);
00184 }
00185
00186 std::pair<bool, value_type> pop() {
00187
00188 unsigned int& cur = concurrent ? cursor.get() : cursor.get(0);
00189 std::pair<bool, value_type> ret = data[cur].pop();
00190 if (ret.first)
00191 return ret;
00192
00193
00194 for (cur = 0; cur < num(); ++cur) {
00195 ret = data[cur].pop();
00196 if (ret.first)
00197 return ret;
00198 }
00199 cur = 0;
00200 return std::pair<bool, value_type>(false, value_type());
00201 }
00202
00203 bool empty() {
00204 for (unsigned int i = 0; i < num(); ++i)
00205 if (!data[i].empty())
00206 return false;
00207 return true;
00208 }
00209
00210 bool aborted(value_type val) {
00211 return push(val);
00212 }
00213
00214
00215
00216 template<typename Iter>
00217 void fill_initial(Iter ii, Iter ee) {
00218 while (ii != ee) {
00219 push(*ii++);
00220 }
00221 }
00222 };
00223 WLCOMPILECHECK(LogOrderByIntegerMetric);
00224
00225 template<typename T, typename Indexer = DummyIndexer<T>, typename LocalTy = FIFO<T>, typename GlobalTy = FIFO<T> >
00226 class LocalFilter {
00227 GlobalTy globalQ;
00228
00229 struct p {
00230 typename LocalTy::template rethread<false>::WL Q;
00231 unsigned int current;
00232 };
00233 PerCPU<p> localQs;
00234 Indexer I;
00235
00236 public:
00237 typedef T value_type;
00238
00239 LocalFilter(const Indexer& x = Indexer()) : I(x) {
00240 for (int i = 0; i < localQs.size(); ++i)
00241 localQs.get(i).current = 0;
00242 }
00243
00245 template<bool newconcurrent>
00246 struct rethread {
00247 typedef LocalFilter WL;
00248 };
00249
00251 bool push(value_type val) OPTNOINLINE {
00252 unsigned int index = I(val);
00253 p& me = localQs.get();
00254 if (index <= me.current)
00255 return me.Q.push(val);
00256 else
00257 return globalQ.push(val);
00258 }
00259
00261 bool aborted(value_type val) {
00262 return push(val);
00263 }
00264
00266 std::pair<bool, value_type> pop() OPTNOINLINE {
00267 std::pair<bool, value_type> r = localQs.get().Q.pop();
00268 if (r.first)
00269 return r;
00270
00271 r = globalQ.pop();
00272 if (r.first)
00273 localQs.get().current = I(r.second);
00274 return r;
00275 }
00276
00278 bool empty() OPTNOINLINE {
00279 if (!localQs.get().Q.empty()) return false;
00280 return globalQ.empty();
00281 }
00282
00284 template<typename iter>
00285 void fill_initial(iter begin, iter end) {
00286 globalQ.fill_initial(begin,end);
00287 }
00288 };
00289 WLCOMPILECHECK(LocalFilter);
00290
00291 #if 0
00292
00293 template<typename T, int chunksize = 64>
00294 class MP_SC_Bag {
00295 class Chunk : public FixedSizeRing<T, chunksize, false>, public ConExtListNode<Chunk>::ListNode {};
00296
00297 MM::FixedSizeAllocator heap;
00298
00299 PerCPU<PtrLock<Chunk*, true> > write_stack;
00300
00301 ConExtLinkedStack<Chunk, true> read_stack;
00302 Chunk* current;
00303
00304 public:
00305 typedef T value_type;
00306
00307 template<bool newconcurrent>
00308 struct rethread {
00309 typedef MP_SC_Bag<T, chunksize> WL;
00310 };
00311
00312 MP_SC_Bag() :heap(sizeof(Chunk)), current(0) {}
00313
00314 bool push(value_type val) {
00315 PtrLock<Chunk*, true>& L = write_stack.get();
00316 L.lock();
00317 Chunk* OldL = L.getValue();
00318 if (OldL && OldL->push_back(val)) {
00319 L.unlock();
00320 return true;
00321 }
00322 Chunk* nc = new (heap.allocate(sizeof(Chunk))) Chunk();
00323 bool retval = nc->push_back(val);
00324 assert(retval);
00325 L.unlock_and_set(nc);
00326 if (OldL)
00327 read_stack.push(OldL);
00328 return true;
00329 }
00330
00331 bool aborted(value_type val) {
00332 return push(val);
00333 }
00334
00335 std::pair<bool, value_type> pop() {
00336
00337 if (!current)
00338 current = read_stack.pop();
00339 if (current)
00340 std::pair<bool, value_type> ret = current->pop_front();
00341 if (ret.first)
00342 return ret;
00343
00344 read_stack.steal(write_stack.get());
00345 ret = read_stack.pop();
00346 if (ret.first)
00347 return ret;
00348
00349 for (int i = 0; i < write_stack.size(); ++i) {
00350 read_stack.steal(write_stack.get(i));
00351 }
00352 return read_stack.pop();
00353 }
00354
00355 bool empty() {
00356 if (!read_stack.empty()) return false;
00357 for (int i = 0; i < write_stack.size(); ++i)
00358 if (!write_stack.get(i).empty())
00359 return false;
00360 return true;
00361 }
00362
00363
00365 template<typename iter>
00366 void fill_initial(iter begin, iter end) {
00367 while (begin != end)
00368 push(*begin++);
00369 }
00370
00371 };
00372 WLCOMPILECHECK(MP_SC_Bag);
00373 #endif
00374
00375
00376 template<typename T, typename LocalWL, typename GlobalWL>
00377 class RequestHirarchy {
00378 public:
00379 typedef T value_type;
00380
00381 private:
00382 PerCPU<typename LocalWL::template rethread<false>::WL> localQueues;
00383 PerLevel<GlobalWL> sharedQueues;
00384 PerLevel<unsigned long> starvingFlags;
00385 GlobalWL gwl;
00386 unsigned long gStarving;
00387
00388
00389
00390 void clearStarving() {
00391 gStarving = 0;
00392 starvingFlags.get() = 0;
00393 }
00394
00395 public:
00396 bool push(value_type val) {
00397 if (gStarved)
00398 return gwl.push(val);
00399 if (starvingFlags.get())
00400 return sharedQueues.push(val);
00401 return localQueues.push(val);
00402 }
00403
00404 bool aborted(value_type val) {
00405 return push(val);
00406 }
00407
00408 std::pair<bool, value_type> pop() {
00409
00410 std::pair<bool, value_type> ret = localQueues.get().pop();
00411 if (ret.first)
00412 return ret;
00413
00414
00415 ret = sharedQueues.get().pop();
00416 if (ret.first) {
00417 clearStarving();
00418 return ret;
00419 }
00420
00421
00422 ret = gwl.pop();
00423 if (ret.first) {
00424 clearStarving();
00425 return ret;
00426 }
00427
00428
00429 starvingFlags.get() = 1;
00430
00431 if (sharedQueues.isFirstInLevel())
00432
00433 return ret;
00434 }
00435
00437 template<typename iter>
00438 void fill_initial(iter begin, iter end) {
00439 gwl.fill_initial(begin,end);
00440 }
00441 };
00442
00443
00444 template<typename T, typename LocalWL, typename DistPolicy>
00445 class ReductionWL {
00446
00447 typedef cache_line_storage<LocalWL> paddedLocalWL;
00448
00449 paddedLocalWL* WL;
00450
00451 FIFO<T> backup;
00452
00453 int starving;
00454
00455 public:
00456
00457 typedef T value_type;
00458
00459 ReductionWL() :starving(0) {
00460 WL = new paddedLocalWL[DistPolicy::getNumIslands()];
00461 }
00462
00463 ~ReductionWL() {
00464 delete[] WL;
00465 WL = 0;
00466 }
00467
00468 bool push(value_type val) {
00469 if (starving)
00470 return backup.push(val);
00471 return WL[DistPolicy::getThreadIsland()].data.push(val);
00472 }
00473
00474 bool aborted(value_type val) {
00475 return WL[DistPolicy::getThreadIsland()].data.aborted(val);
00476 }
00477
00478 std::pair<bool, value_type> pop() {
00479 int myIsland = DistPolicy::getThreadIsland();
00480 std::pair<bool, value_type> val = WL[myIsland].data.pop();
00481 if (val.first || !DistPolicy::isThreadMaster())
00482 return val;
00483
00484 int IFlag = 1 << myIsland;
00485
00486 val = backup.pop();
00487 if (val.first) {
00488 __sync_fetch_and_and(&starving, ~IFlag);
00489 return val;
00490 }
00491 if (!starving & IFlag)
00492 __sync_fetch_and_or(&starving, IFlag);
00493 return val;
00494 }
00495
00496 template<typename iter>
00497 void fillInitial(iter begin, iter end) {
00498 return gwl.fill_initial(begin,end);
00499 }
00500 };
00501
00502
00503 #if 0
00504 template<class T, class Indexer, typename ContainerTy = FIFO<T>, bool concurrent=true>
00505 class dOrderByIntegerMetric : private boost::noncopyable {
00506
00507 struct LevelItem {
00508 unsigned int cur_pri;
00509 unsigned int set_pri;
00510 ContainerTy* cur;
00511 };
00512
00513 PerLevel<LevelItem> items;
00514 unsigned int global_min;
00515
00516 std::map<unsigned int, ContainerTy*> data;
00517 SimpleLock<int, concurrent> mapLock;
00518
00519 public:
00520
00521 typedef T value_type;
00522 template<bool newconcurrent>
00523 struct rethread {
00524 typedef dOrderByIntegerMetric<T, Indexer, typename ContainerTy::template rethread<newconcurrent>::WL, newconcurrent> WL;
00525 };
00526
00527 dOrderByIntegerMetric(const Indexer& x = Indexer())
00528 :I(x), numActive(getSystemThreadPool().getActiveThreads())
00529 {
00530
00531 }
00532
00533 bool push(value_type val) {
00534 unsigned int index = I(val);
00535 data[index].push(val);
00536 }
00537
00538 std::pair<bool, value_type> pop() {
00539
00540 unsigned int& cur = cursor.get();
00541 std::pair<bool, value_type> ret = data[cur].pop();
00542 if (ret.first)
00543 return ret;
00544
00545
00546 for (int i = 0; i < (num() + active() - 1) / active(); ++i) {
00547 cur += active();
00548 if (cur >= num())
00549 cur %= active();
00550 ret = data[cur].try_pop();
00551 if (ret.first)
00552 return ret;
00553 }
00554 return std::pair<bool, value_type>(false, value_type());
00555 }
00556
00557 std::pair<bool, value_type> try_pop() {
00558 return pop();
00559 }
00560
00561 bool empty() {
00562 for (unsigned int i = 0; i < num(); ++i)
00563 if (!data[i].empty())
00564 return false;
00565 return true;
00566 }
00567
00568 bool aborted(value_type val) {
00569 return push(val);
00570 }
00571
00572
00573
00574 template<typename Iter>
00575 void fill_initial(Iter ii, Iter ee) {
00576 while (ii != ee) {
00577 push(*ii++);
00578 }
00579 }
00580 };
00581 #endif
00582
00583 #if 0
00584 template<typename T>
00585 class GWL_ChaseLev_Dyn : private boost::noncopyable {
00586
00587 struct DequeNode {
00588 enum { ArraySize = 256 };
00589 T itsDataArr[ArraySize];
00590 DequeNode* next;
00591 DequeNode* prev;
00592 };
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606 volatile uint64_t Bottom;
00607 volatile uint64_t Top;
00608
00609 uint64_t ReadBottom() {
00610
00611 return Bottom;
00612 }
00613
00614 uint64_t ReadTop() {
00615
00616 return Top;
00617 }
00618
00619 void WriteBottom(uint64_t V) {
00620
00621 Bottom = V;
00622 }
00623 void WriteTop(uint64_t V) {
00624
00625 Top = V;
00626 }
00627
00628
00629
00630 void DecodeBottom(uint64_t v, DequeNode*& currNode, uint8_t& currIndex) {
00631 currNode = (DequeNode*)(v & 0x0000FFFFFFFFFFFFULL);
00632 currIndex = (uint8_t)((v >> 48) & 0x0FFFF);
00633 }
00634 uint64_t EncodeBottom(DequeNode* currNode, uint8_t currIndex) {
00635 uint64_t v = 0;
00636 v = (uint64_t)currNode;
00637 v |= (uint64_t)currIndex << 48;
00638 return v;
00639 }
00640
00641 void DecodeTop(uint64_t v, uint8_t& currTopTag, DequeNode*& currTopNode, uint8_t& currTopIndex) {
00642 currTopNode = (DequeNode*)(v & 0x0000FFFFFFFFFFFFULL);
00643 currTopIndex = (uint8_t)((v >> 48) & 0x0FFFF);
00644 currTopTag = (uint8_t)((v >> 56) & 0x0FFFF);
00645 }
00646 uint64_t EncodeTop(uint8_t currTopTag, DequeNode* currTopNode, uint8_t currTopIndex) {
00647 uint64_t v = 0;
00648 v = (uint64_t)currTopNode;
00649 v |= (uint64_t)currTopIndex << 48;
00650 v |= (uint64_t)currTopTag << 56;
00651 return v;
00652 }
00653
00654 bool CAS(volatile uint64_t* ptr, uint64_t old, uint64_t val) {
00655 return __sync_bool_compare_and_swap(ptr,old,val);
00656 }
00657
00658 DequeNode* AllocateNode() {
00659 return new DequeNode;
00660 }
00661
00662 bool emptinessTest(uint64_t bottomVal, uint64_t topVal) {
00663 DequeNode* botNode = 0;
00664 uint8_t botCellIndex = 0;
00665 DecodeBottom(bottomVal,botNode,botCellIndex);
00666 uint8_t topTag = 0;
00667 DequeNode* topNode = 0;
00668 uint8_t topCellIndex = 0;
00669 DecodeTop(topVal, topTag,topNode,topCellIndex);
00670 if ((botNode==topNode) && (botCellIndex==topCellIndex ||
00671 botCellIndex==(topCellIndex+1))) {
00672 return true;
00673 } else if ((botNode==topNode->next) && (botCellIndex==0) &&
00674 (topCellIndex==(DequeNode::ArraySize-1))) {
00675 return true;
00676 }
00677 return false;
00678 }
00679
00680
00681 void PushBottom(T theData) {
00682 DequeNode* currNode = 0;
00683 uint8_t currIndex = 0;
00684 DequeNode* newNode = 0;
00685 uint8_t newIndex = 0;
00686 DecodeBottom(ReadBottom(),currNode, currIndex);
00687 currNode->itsDataArr[currIndex] = theData;
00688
00689
00690 if (currIndex != 0) {
00691 newNode = currNode;
00692 newIndex = currIndex - 1;
00693 } else {
00694 newNode = AllocateNode();
00695 newNode->next = currNode;
00696 currNode->prev = newNode;
00697 newIndex = DequeNode::ArraySize - 1;
00698 }
00699
00700 WriteBottom(EncodeBottom(newNode,newIndex));
00701 }
00702
00703
00704 T PopTop(bool& EMPTY, bool& ABORT) {
00705 EMPTY = false;
00706 ABORT = false;
00707 uint64_t currTop = ReadTop();
00708 uint8_t currTopTag = 0;
00709 uint8_t currTopIndex = 0;
00710 DequeNode* currTopNode = 0;
00711 uint8_t newTopTag = 0;
00712 uint8_t newTopIndex = 0;
00713 DequeNode* newTopNode = 0;
00714 DequeNode* nodeToFree = 0;
00715 DecodeTop(currTop, currTopTag, currTopNode, currTopIndex);
00716 uint64_t currBottom = ReadBottom();
00717 if (emptinessTest(currBottom, currTop)) {
00718 if (currTop == ReadTop()) {
00719 EMPTY = true;
00720 return T();
00721 } else {
00722 ABORT = true;
00723 return T();
00724 }
00725 }
00726 if (currTopIndex != 0) {
00727 newTopTag = currTopTag;
00728 newTopNode = currTopNode;
00729 newTopIndex = currTopIndex - 1;
00730 } else {
00731 nodeToFree = currTopNode->next;
00732 newTopTag = currTopTag + 1;
00733 newTopNode = currTopNode->prev;
00734 newTopIndex = DequeNode::ArraySize - 1;
00735 }
00736 uint64_t newTopVal = EncodeTop(newTopTag, newTopNode, newTopIndex);
00737 T retVal = currTopNode->itsDataArr[currTopIndex];
00738 if (CAS(&Top, currTop, newTopVal)) {
00739 if (nodeToFree)
00740 delete nodeToFree;
00741 return retVal;
00742 } else {
00743 ABORT = true;
00744 return T();
00745 }
00746 }
00747
00748
00749 bool Empty() {
00750 return emptinessTest(ReadBottom(), ReadTop());
00751 }
00752
00753
00754 T PopBottom(bool& EMPTY) {
00755 EMPTY = false;
00756 DequeNode* oldBotNode = 0;
00757 uint8_t oldBotIndex = 0;
00758 DequeNode* newBotNode = 0;
00759 uint8_t newBotIndex = 0;
00760 uint64_t oldBotVal = ReadBottom();
00761 DecodeBottom(oldBotVal, oldBotNode, oldBotIndex);
00762 if (oldBotIndex != DequeNode::ArraySize-1) {
00763 newBotNode = oldBotNode;
00764 newBotIndex = oldBotIndex+1;
00765 } else {
00766 newBotNode = oldBotNode->next;
00767 newBotIndex = 0;
00768 }
00769
00770 uint64_t newBotVal = EncodeBottom(newBotNode,newBotIndex);
00771 WriteBottom(newBotVal);
00772 uint64_t currTop = ReadTop();
00773 uint8_t currTopTag = 0;
00774 DequeNode* currTopNode = 0;
00775 uint8_t currTopIndex = 0;
00776 DecodeTop(currTop, currTopTag,currTopNode,currTopIndex);
00777 T retVal = newBotNode->itsDataArr[newBotIndex];
00778
00779 if (oldBotNode == currTopNode && oldBotIndex == currTopIndex ) {
00780
00781
00782 WriteBottom(EncodeBottom(oldBotNode,oldBotIndex));
00783 EMPTY = true;
00784
00785 return T();
00786 } else if ( newBotNode == currTopNode && newBotIndex == currTopIndex ) {
00787
00788
00789
00790
00791 uint64_t newTopVal = EncodeTop(currTopTag+1, currTopNode, currTopIndex);
00792 if (CAS(&Top, currTop, newTopVal)) {
00793 if (oldBotNode != newBotNode)
00794 delete oldBotNode;
00795 return retVal;
00796 } else {
00797
00798
00799 WriteBottom(EncodeBottom(oldBotNode,oldBotIndex));
00800 EMPTY = true;
00801
00802 return T();
00803 }
00804 } else {
00805
00806 if (oldBotNode != newBotNode)
00807 delete oldBotNode;
00808 return retVal;
00809 }
00810 }
00811
00812 public:
00813
00814 typedef GWL_ChaseLev_Dyn<T> ConcurrentTy;
00815 typedef GWL_ChaseLev_Dyn<T> SingleTy;
00816 enum {MAYSTEAL = true};
00817
00818
00819 GWL_ChaseLev_Dyn()
00820 :Bottom(0), Top(0)
00821 {
00822 DequeNode* nodeA = AllocateNode();
00823 DequeNode* nodeB = AllocateNode();
00824 nodeA->prev = 0;
00825 nodeA->next = nodeB;
00826 nodeB->next = 0;
00827 nodeB->prev = nodeA;
00828 int newIndex = DequeNode::ArraySize - 1;
00829 WriteBottom(EncodeBottom(nodeA,newIndex));
00830 WriteTop(EncodeTop(0,nodeA,newIndex));
00831 }
00832
00833
00834
00835 void push(T val) {
00836 PushBottom(val);
00837 }
00838
00839 T pop(bool& succeeded) {
00840 bool Emp;
00841 T retval = PopBottom(Emp);
00842 succeeded = !Emp;
00843 return retval;
00844 }
00845
00846
00847 T steal(bool& succeeded) {
00848 bool Empty, Abort;
00849 T retval = PopTop(Empty,Abort);
00850 succeeded = !(Empty || Abort);
00851 return retval;
00852 }
00853
00854 bool empty() {
00855 return Empty();
00856 }
00857
00858 };
00859
00860 template<typename T>
00861 class GWL_Idempotent_LIFO : private boost::noncopyable {
00862
00863 packedInt2<32,32> anchor;
00864 unsigned int capacity;
00865 T* volatile tasks;
00866
00867 inline void order() {
00868
00869 __asm__("":::"memory");
00870 }
00871
00872 bool Empty() {
00873 unsigned int t,g;
00874 anchor.packedRead(t,g);
00875 return t == 0;
00876 }
00877
00878 void put(T t_ask) {
00879
00880 unsigned int t,g;
00881 anchor.packedRead(t,g);
00882 if (t == capacity) {
00883 expand();
00884 put(t_ask);
00885 return;
00886 }
00887 tasks[t] = t_ask;
00888 order();
00889 anchor.packedWrite(t+1,g+1);
00890 }
00891
00892 T take(bool& EMPTY) {
00893 EMPTY = false;
00894 unsigned int t,g;
00895 anchor.packedRead(t,g);
00896 if (t == 0) {
00897 EMPTY = true;
00898 return T();
00899 }
00900 T t_ask = tasks[t-1];
00901 anchor.packedWrite(t-1,g);
00902 return t_ask;
00903 }
00904
00905 T i_steal(bool& EMPTY) {
00906 EMPTY = false;
00907
00908
00909 unsigned int t,g;
00910 anchor.packedRead(t,g);
00911 if (t == 0) {
00912 EMPTY = true;
00913 return T();
00914 }
00915 order();
00916 T* a = tasks;
00917 T t_ask = a[t-1];
00918 order();
00919 if (!anchor.CAS(t,g, t-1,g )) {
00920 return i_steal(EMPTY);
00921 }
00922 return t_ask;
00923 }
00924
00925 void expand() {
00926
00927
00928 T* a = new T[2*capacity];
00929 for( int i = 0; i < (int)capacity; ++i)
00930 a[i] = tasks[i];
00931 order();
00932 tasks = a;
00933 capacity = 2*capacity;
00934 order();
00935 }
00936
00937 public:
00938 typedef GWL_Idempotent_LIFO<T> ConcurrentTy;
00939 typedef GWL_Idempotent_LIFO<T> SingleTy;
00940 enum {MAYSTEAL = true};
00941
00942 GWL_Idempotent_LIFO(int size = 256)
00943 :anchor(0,0), capacity(size)
00944 {
00945 tasks = new T[size];
00946 }
00947
00948 void push(T val) {
00949 put(val);
00950 }
00951
00952 T pop(bool& succeeded) {
00953 bool Empty;
00954 T retval = take(Empty);
00955 succeeded = !Empty;
00956 return retval;
00957 }
00958
00959
00960 T steal(bool& succeeded) {
00961 bool Empty;
00962 T retval = i_steal(Empty);
00963 succeeded = !Empty;
00964 return retval;
00965 }
00966
00967 bool empty() {
00968 return Empty();
00969 }
00970
00971 };
00972
00973
00974 template<typename T>
00975 class GWL_Idempotent_FIFO : private boost::noncopyable {
00976
00977 struct TaskArrayWithSize {
00978 int size;
00979 T array[1];
00980 };
00981
00982 TaskArrayWithSize* mkArray(int num) {
00983 TaskArrayWithSize* r = (TaskArrayWithSize*)malloc(sizeof(TaskArrayWithSize)+sizeof(T[num]));
00984 r->size = num;
00985 return r;
00986 }
00987
00988 int head;
00989 int tail;
00990 TaskArrayWithSize* volatile tasks;
00991
00992 inline void order() {
00993
00994 __asm__("":::"memory");
00995 }
00996
00997 bool Empty() {
00998 return head == tail;
00999 }
01000
01001 void put(T t_ask) {
01002
01003 int h = head;
01004 int t = tail;
01005 if (t == h+tasks->size) {
01006 expand();
01007 put(t_ask);
01008 return;
01009 }
01010 tasks->array[t%tasks->size] = t_ask;
01011 order();
01012 tail = t+1;
01013 }
01014
01015 T take(bool& EMPTY) {
01016 EMPTY = false;
01017 int h = head;
01018 int t = tail;
01019 if (h == t) {
01020 EMPTY = true;
01021 return T();
01022 }
01023 T t_ask = tasks->array[h%tasks->size];
01024 head = h+1;
01025 return t_ask;
01026 }
01027
01028 T i_steal(bool& EMPTY) {
01029 EMPTY = false;
01030
01031
01032
01033 int h = head;
01034 order();
01035 int t = tail;
01036 order();
01037 if (h == t) {
01038 EMPTY = true;
01039 return T();
01040 }
01041 TaskArrayWithSize* a = tasks;
01042 T t_ask = a->array[h%a->size];
01043 order();
01044 if (!__sync_bool_compare_and_swap(&head,h,h+1)) {
01045 return i_steal(EMPTY);
01046 }
01047 return t_ask;
01048 }
01049
01050 void expand() {
01051
01052
01053 int size = tasks->size;
01054 TaskArrayWithSize* a = mkArray(2*size);
01055 for (int i = head; i < tail; ++i)
01056 a->array[i%a->size] = tasks->array[i%tasks->size];
01057 order();
01058 tasks = a;
01059 order();
01060 }
01061
01062 public:
01063 typedef GWL_Idempotent_FIFO<T> ConcurrentTy;
01064 typedef GWL_Idempotent_FIFO<T> SingleTy;
01065 enum {MAYSTEAL = true};
01066
01067 GWL_Idempotent_FIFO(int size = 256)
01068 :head(0), tail(0)
01069 {
01070 tasks = mkArray(size);
01071 }
01072
01073 void push(T val) {
01074 put(val);
01075 }
01076
01077 T pop(bool& succeeded) {
01078 bool Empty;
01079 T retval = take(Empty);
01080 succeeded = !Empty;
01081 return retval;
01082 }
01083
01084
01085 T steal(bool& succeeded) {
01086 bool Empty;
01087 T retval = i_steal(Empty);
01088 succeeded = !Empty;
01089 return retval;
01090 }
01091
01092 bool empty() {
01093 return Empty();
01094 }
01095
01096 };
01097
01098
01099 template<typename T>
01100 class GWL_Idempotent_FIFO_SB : private boost::noncopyable {
01101
01102 struct TaskArrayWithSize {
01103 int size;
01104 T array[1];
01105 };
01106
01107 TaskArrayWithSize* mkArray(int num) {
01108 TaskArrayWithSize* r = (TaskArrayWithSize*)malloc(sizeof(TaskArrayWithSize)+sizeof(T[num]));
01109 r->size = num;
01110 return r;
01111 }
01112
01113 packedInt3<21,21,22> anchor;
01114 TaskArrayWithSize* volatile tasks;
01115
01116 inline void order() {
01117
01118 __asm__("":::"memory");
01119 }
01120
01121
01122 bool Empty() {
01123 unsigned int h,s,g;
01124 anchor.packedRead(h,s,g);
01125 return s == 0;
01126 }
01127
01128 void put(T t_ask) {
01129
01130 unsigned int h,s,g;
01131 anchor.packedRead(h,s,g);
01132 if ((int)s == tasks->size) {
01133 expand();
01134 put(t_ask);
01135 return;
01136 }
01137 tasks->array[(h+s)%tasks->size] = t_ask;
01138 order();
01139 anchor.packedWrite(h,s+1,g+1);
01140 }
01141
01142 T take(bool& EMPTY) {
01143 EMPTY = false;
01144 unsigned int h,s,g;
01145 anchor.packedRead(h,s,g);
01146 if (s == 0) {
01147 EMPTY = true;
01148 return T();
01149 }
01150 T t_ask = tasks->array[(h+s-1)%tasks->size];
01151 anchor.packedWrite(h,s-1,g);
01152 return t_ask;
01153 }
01154
01155 T i_steal(bool& EMPTY) {
01156 EMPTY = false;
01157
01158
01159 unsigned int h,s,g;
01160 anchor.packedRead(h,s,g);
01161 if (s == 0) {
01162 EMPTY = 0;
01163 return T();
01164 }
01165 order();
01166 TaskArrayWithSize* a = tasks;
01167 T t_ask = a->array[h%a->size];
01168 unsigned int h2 = (h+1) % a->size;
01169 order();
01170 if (!anchor.CAS(h,s,g , h2,s-1,g )) {
01171 return i_steal(EMPTY);
01172 }
01173 return t_ask;
01174 }
01175
01176 void expand() {
01177
01178
01179 unsigned int h,s,g;
01180 anchor.packedRead(h,s,g);
01181 TaskArrayWithSize* a = mkArray(2*s);
01182 for (unsigned int i = 0; i < s; ++i)
01183 a->array[(h+i)%a->size] = tasks->array[(h+i)%tasks->size];
01184 order();
01185 tasks = a;
01186 order();
01187 }
01188
01189 public:
01190 typedef GWL_Idempotent_FIFO_SB<T> ConcurrentTy;
01191 typedef GWL_Idempotent_FIFO_SB<T> SingleTy;
01192 enum {MAYSTEAL = true};
01193
01194 GWL_Idempotent_FIFO_SB()
01195 :anchor(0,0,0)
01196 {
01197
01198 tasks = mkArray(256);
01199 }
01200
01201 void push(T val) {
01202 put(val);
01203 }
01204
01205 T pop(bool& succeeded) {
01206 bool Empty;
01207 T retval = take(Empty);
01208 succeeded = !Empty;
01209 return retval;
01210 }
01211
01212
01213 T steal(bool& succeeded) {
01214 bool Empty;
01215 T retval = i_steal(Empty);
01216 succeeded = !Empty;
01217 return retval;
01218 }
01219
01220 bool empty() {
01221 return Empty();
01222 }
01223
01224 };
01225 #endif
01226
01227 }
01228 }
01229 }
01230
01231 #endif