X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FAtomicIntrusiveLinkedList.h;h=c0ee1b144274a8252f924355140e95a12b4c7612;hb=61fbd6698139d3f797401da6350371c7afc4030c;hp=e74554220123a1bf7dc93a6edffdefdfe2e66a43;hpb=36f174f920a35c7de58906b216008f8b56bd7231;p=folly.git diff --git a/folly/AtomicIntrusiveLinkedList.h b/folly/AtomicIntrusiveLinkedList.h index e7455422..c0ee1b14 100644 --- a/folly/AtomicIntrusiveLinkedList.h +++ b/folly/AtomicIntrusiveLinkedList.h @@ -1,5 +1,5 @@ /* - * Copyright 2016 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ #include #include +#include namespace folly { @@ -104,15 +105,31 @@ class AtomicIntrusiveLinkedList { void sweep(F&& func) { while (auto head = head_.exchange(nullptr)) { auto rhead = reverse(head); - while (rhead != nullptr) { - auto t = rhead; - rhead = next(t); - next(t) = nullptr; - func(t); - } + unlinkAll(rhead, std::forward(func)); } } + /** + * Similar to sweep() but calls func() on elements in LIFO order. + * + * func() is called for all elements in the list at the moment + * reverseSweep() is called. Unlike sweep() it does not loop to ensure the + * list is empty at some point after the last invocation. This way callers + * can reason about the ordering: elements inserted since the last call to + * reverseSweep() will be provided in LIFO order. + * + * Example: if elements are inserted in the order 1-2-3, the callback is + * invoked 3-2-1. If the callback moves elements onto a stack, popping off + * the stack will produce the original insertion order 1-2-3. + */ + template + void reverseSweep(F&& func) { + // We don't loop like sweep() does because the overall order of callbacks + // would be strand-wise LIFO which is meaningless to callers. + auto head = head_.exchange(nullptr); + unlinkAll(head, std::forward(func)); + } + private: std::atomic head_{nullptr}; @@ -132,6 +149,18 @@ class AtomicIntrusiveLinkedList { } return rhead; } + + /* Unlinks all elements in the linked list fragment pointed to by `head', + * calling func() on every element */ + template + void unlinkAll(T* head, F&& func) { + while (head != nullptr) { + auto t = head; + head = next(t); + next(t) = nullptr; + func(t); + } + } }; } // namespace folly